diff -Nru snapd-2.0.5/asserts/account.go snapd-2.0.8/asserts/account.go
--- snapd-2.0.5/asserts/account.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/asserts/account.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,83 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package asserts
+
+import "time"
+
+var (
+ accountValidationCertified = "certified"
+)
+
+// Account holds an account assertion, which ties a name for an account
+// to its identifier and provides the authority's confidence in the name's validity.
+type Account struct {
+ assertionBase
+ certified bool
+ timestamp time.Time
+}
+
+// AccountID returns the account-id of the account.
+func (acc *Account) AccountID() string {
+ return acc.Header("account-id")
+}
+
+// Username returns the user name for the account.
+func (acc *Account) Username() string {
+ return acc.Header("username")
+}
+
+// DisplayName returns the human-friendly name for the account.
+func (acc *Account) DisplayName() string {
+ return acc.Header("display-name")
+}
+
+// IsCertified returns true if the authority has confidence in the account's name.
+func (acc *Account) IsCertified() bool {
+ return acc.certified
+}
+
+// Timestamp returns the time when the account was issued.
+func (acc *Account) Timestamp() time.Time {
+ return acc.timestamp
+}
+
+func assembleAccount(assert assertionBase) (Assertion, error) {
+ _, err := checkNotEmpty(assert.headers, "display-name")
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = checkNotEmpty(assert.headers, "validation")
+ if err != nil {
+ return nil, err
+ }
+ certified := assert.headers["validation"] == accountValidationCertified
+
+ timestamp, err := checkRFC3339Date(assert.headers, "timestamp")
+ if err != nil {
+ return nil, err
+ }
+
+ return &Account{
+ assertionBase: assert,
+ certified: certified,
+ timestamp: timestamp,
+ }, nil
+}
diff -Nru snapd-2.0.5/asserts/account_key.go snapd-2.0.8/asserts/account_key.go
--- snapd-2.0.5/asserts/account_key.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/account_key.go 2016-06-08 05:58:01.000000000 +0000
@@ -73,14 +73,14 @@
if err != nil {
return nil, err
}
- fp, err := checkMandatory(ab.headers, fingerprintName)
+ fp, err := checkNotEmpty(ab.headers, fingerprintName)
if err != nil {
return nil, err
}
if fp != pubKey.Fingerprint() {
return nil, fmt.Errorf("public key does not match provided fingerprint")
}
- keyID, err := checkMandatory(ab.headers, keyIDName)
+ keyID, err := checkNotEmpty(ab.headers, keyIDName)
if err != nil {
return nil, err
}
diff -Nru snapd-2.0.5/asserts/account_key_test.go snapd-2.0.8/asserts/account_key_test.go
--- snapd-2.0.5/asserts/account_key_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/account_key_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
type accountKeySuite struct {
@@ -45,7 +45,7 @@
}
accDb, err := asserts.OpenDatabase(cfg1)
c.Assert(err, IsNil)
- pk := asserts.OpenPGPPrivateKey(testPrivKey1)
+ pk := testPrivKey1
err = accDb.ImportKey("acc-id1", pk)
c.Assert(err, IsNil)
aks.fp = pk.PublicKey().Fingerprint()
@@ -104,12 +104,19 @@
invalidHeaderTests := []struct{ original, invalid, expectedErr string }{
{"account-id: acc-id1\n", "", `"account-id" header is mandatory`},
+ {"account-id: acc-id1\n", "account-id: \n", `"account-id" header should not be empty`},
+ {"public-key-id: " + aks.keyid + "\n", "", `"public-key-id" header is mandatory`},
+ {"public-key-id: " + aks.keyid + "\n", "public-key-id: \n", `"public-key-id" header should not be empty`},
+ {"public-key-fingerprint: " + aks.fp + "\n", "", `"public-key-fingerprint" header is mandatory`},
+ {"public-key-fingerprint: " + aks.fp + "\n", "public-key-fingerprint: \n", `"public-key-fingerprint" header should not be empty`},
{aks.sinceLine, "", `"since" header is mandatory`},
- {aks.untilLine, "", `"until" header is mandatory`},
+ {aks.sinceLine, "since: \n", `"since" header should not be empty`},
{aks.sinceLine, "since: 12:30\n", `"since" header is not a RFC3339 date: .*`},
+ {aks.sinceLine, "since: \n", `"since" header should not be empty`},
+ {aks.untilLine, "", `"until" header is mandatory`},
+ {aks.untilLine, "until: \n", `"until" header should not be empty`},
{aks.untilLine, "until: " + aks.since.Format(time.RFC3339) + "\n", `invalid 'since' and 'until' times \(no gap after 'since' till 'until'\)`},
- {"public-key-id: " + aks.keyid + "\n", "", `"public-key-id" header is mandatory`},
- {"public-key-fingerprint: " + aks.fp + "\n", "", `"public-key-fingerprint" header is mandatory`},
+ {aks.untilLine, "until: \n", `"until" header should not be empty`},
}
for _, test := range invalidHeaderTests {
@@ -188,7 +195,7 @@
cfg := &asserts.DatabaseConfig{
Backstore: bs,
KeypairManager: asserts.NewMemoryKeypairManager(),
- TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", &trustedKey.PublicKey)},
+ TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
}
db, err := asserts.OpenDatabase(cfg)
c.Assert(err, IsNil)
@@ -206,7 +213,7 @@
"since": aks.since.Format(time.RFC3339),
"until": aks.until.Format(time.RFC3339),
}
- accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), asserts.OpenPGPPrivateKey(trustedKey))
+ accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey)
c.Assert(err, IsNil)
db := aks.openDB(c)
@@ -226,7 +233,7 @@
"since": aks.since.Format(time.RFC3339),
"until": aks.until.Format(time.RFC3339),
}
- accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), asserts.OpenPGPPrivateKey(trustedKey))
+ accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey)
c.Assert(err, IsNil)
db := aks.openDB(c)
diff -Nru snapd-2.0.5/asserts/account_test.go snapd-2.0.8/asserts/account_test.go
--- snapd-2.0.5/asserts/account_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/asserts/account_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,134 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package asserts_test
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/snapcore/snapd/asserts"
+ . "gopkg.in/check.v1"
+)
+
+var (
+ _ = Suite(&accountSuite{})
+)
+
+type accountSuite struct {
+ ts time.Time
+ tsLine string
+}
+
+func (s *accountSuite) SetUpSuite(c *C) {
+ s.ts = time.Now().Truncate(time.Second).UTC()
+ s.tsLine = "timestamp: " + s.ts.Format(time.RFC3339) + "\n"
+}
+
+const accountExample = "type: account\n" +
+ "authority-id: canonical\n" +
+ "account-id: abc-123\n" +
+ "display-name: Nice User\n" +
+ "username: nice\n" +
+ "validation: certified\n" +
+ "TSLINE" +
+ "body-length: 0" +
+ "\n\n" +
+ "openpgp c2ln"
+
+func (s *accountSuite) TestDecodeOK(c *C) {
+ encoded := strings.Replace(accountExample, "TSLINE", s.tsLine, 1)
+ a, err := asserts.Decode([]byte(encoded))
+ c.Assert(err, IsNil)
+ c.Check(a.Type(), Equals, asserts.AccountType)
+ account := a.(*asserts.Account)
+ c.Check(account.AuthorityID(), Equals, "canonical")
+ c.Check(account.Timestamp(), Equals, s.ts)
+ c.Check(account.AccountID(), Equals, "abc-123")
+ c.Check(account.DisplayName(), Equals, "Nice User")
+ c.Check(account.Username(), Equals, "nice")
+ c.Check(account.IsCertified(), Equals, true)
+}
+
+func (s *accountSuite) TestIsCertified(c *C) {
+ tests := []struct {
+ value string
+ isCertified bool
+ }{
+ {"certified", true},
+ {"unproven", false},
+ {"nonsense", false},
+ }
+
+ template := strings.Replace(accountExample, "TSLINE", s.tsLine, 1)
+ for _, test := range tests {
+ encoded := strings.Replace(
+ template,
+ "validation: certified\n",
+ fmt.Sprintf("validation: %s\n", test.value),
+ 1,
+ )
+ assert, err := asserts.Decode([]byte(encoded))
+ c.Assert(err, IsNil)
+ account := assert.(*asserts.Account)
+ c.Check(account.IsCertified(), Equals, test.isCertified)
+ }
+}
+
+const (
+ accountErrPrefix = "assertion account: "
+)
+
+func (s *accountSuite) TestDecodeInvalid(c *C) {
+ encoded := strings.Replace(accountExample, "TSLINE", s.tsLine, 1)
+
+ invalidTests := []struct{ original, invalid, expectedErr string }{
+ {"account-id: abc-123\n", "", `"account-id" header is mandatory`},
+ {"account-id: abc-123\n", "account-id: \n", `"account-id" header should not be empty`},
+ {"display-name: Nice User\n", "", `"display-name" header is mandatory`},
+ {"display-name: Nice User\n", "display-name: \n", `"display-name" header should not be empty`},
+ {"validation: certified\n", "", `"validation" header is mandatory`},
+ {"validation: certified\n", "validation: \n", `"validation" header should not be empty`},
+ {s.tsLine, "", `"timestamp" header is mandatory`},
+ {s.tsLine, "timestamp: \n", `"timestamp" header should not be empty`},
+ {s.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
+ }
+
+ for _, test := range invalidTests {
+ invalid := strings.Replace(encoded, test.original, test.invalid, 1)
+ _, err := asserts.Decode([]byte(invalid))
+ c.Check(err, ErrorMatches, accountErrPrefix+test.expectedErr)
+ }
+}
+
+func (s *accountSuite) TestCheckInconsistentTimestamp(c *C) {
+ ex, err := asserts.Decode([]byte(strings.Replace(accountExample, "TSLINE", s.tsLine, 1)))
+ c.Assert(err, IsNil)
+
+ signingKeyID, accSignDB, db := makeSignAndCheckDbWithAccountKey(c, "canonical")
+
+ headers := ex.Headers()
+ headers["timestamp"] = "2011-01-01T14:00:00Z"
+ account, err := accSignDB.Sign(asserts.AccountType, headers, nil, signingKeyID)
+ c.Assert(err, IsNil)
+
+ err = db.Check(account)
+ c.Assert(err, ErrorMatches, "account assertion timestamp outside of signing key validity")
+}
diff -Nru snapd-2.0.5/asserts/asserts.go snapd-2.0.8/asserts/asserts.go
--- snapd-2.0.5/asserts/asserts.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/asserts.go 2016-06-08 05:58:01.000000000 +0000
@@ -44,10 +44,10 @@
// Understood assertion types.
var (
+ AccountType = &AssertionType{"account", []string{"account-id"}, assembleAccount}
AccountKeyType = &AssertionType{"account-key", []string{"account-id", "public-key-id"}, assembleAccountKey}
- DeviceSerialType = &AssertionType{"device-serial", []string{"brand-id", "model", "serial"}, assembleDeviceSerial}
- IdentityType = &AssertionType{"identity", []string{"account-id"}, assembleIdentity}
ModelType = &AssertionType{"model", []string{"series", "brand-id", "model"}, assembleModel}
+ SerialType = &AssertionType{"serial", []string{"brand-id", "model", "serial"}, assembleSerial}
SnapDeclarationType = &AssertionType{"snap-declaration", []string{"series", "snap-id"}, assembleSnapDeclaration}
SnapBuildType = &AssertionType{"snap-build", []string{"series", "snap-id", "snap-digest"}, assembleSnapBuild}
SnapRevisionType = &AssertionType{"snap-revision", []string{"series", "snap-id", "snap-digest"}, assembleSnapRevision}
@@ -56,10 +56,10 @@
)
var typeRegistry = map[string]*AssertionType{
+ AccountType.Name: AccountType,
AccountKeyType.Name: AccountKeyType,
- IdentityType.Name: IdentityType,
ModelType.Name: ModelType,
- DeviceSerialType.Name: DeviceSerialType,
+ SerialType.Name: SerialType,
SnapDeclarationType.Name: SnapDeclarationType,
SnapBuildType.Name: SnapBuildType,
SnapRevisionType.Name: SnapRevisionType,
@@ -472,11 +472,11 @@
return nil, fmt.Errorf("assertion body length and declared body-length don't match: %v != %v", len(body), length)
}
- if _, err := checkMandatory(headers, "authority-id"); err != nil {
+ if _, err := checkNotEmpty(headers, "authority-id"); err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
- typ, err := checkMandatory(headers, "type")
+ typ, err := checkNotEmpty(headers, "type")
if err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
@@ -486,7 +486,7 @@
}
for _, primKey := range assertType.PrimaryKey {
- if _, err := checkMandatory(headers, primKey); err != nil {
+ if _, err := checkNotEmpty(headers, primKey); err != nil {
return nil, fmt.Errorf("assertion %s: %v", assertType.Name, err)
}
}
@@ -543,7 +543,7 @@
finalHeaders["type"] = assertType.Name
finalHeaders["body-length"] = strconv.Itoa(bodyLength)
- if _, err := checkMandatory(finalHeaders, "authority-id"); err != nil {
+ if _, err := checkNotEmpty(finalHeaders, "authority-id"); err != nil {
return nil, err
}
@@ -568,7 +568,7 @@
"body-length": true,
}
for _, primKey := range assertType.PrimaryKey {
- if _, err := checkMandatory(finalHeaders, primKey); err != nil {
+ if _, err := checkNotEmpty(finalHeaders, primKey); err != nil {
return nil, err
}
writeHeader(buf, finalHeaders, primKey)
@@ -604,7 +604,7 @@
signature, err := signContent(content, privKey)
if err != nil {
- return nil, fmt.Errorf("failed to sign assertion: %v", err)
+ return nil, fmt.Errorf("cannot sign assertion: %v", err)
}
// be 'cat' friendly, add a ignored newline to the signature which is the last part of the encoded assertion
signature = append(signature, '\n')
diff -Nru snapd-2.0.5/asserts/asserts_test.go snapd-2.0.8/asserts/asserts_test.go
--- snapd-2.0.5/asserts/asserts_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/asserts_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
type assertsSuite struct{}
@@ -394,7 +394,7 @@
"authority-id": "auth-id1",
"primary-key": "0",
}
- a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, asserts.OpenPGPPrivateKey(testPrivKey1))
+ a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1)
c.Assert(err, IsNil)
_, err = asserts.Decode(asserts.Encode(a))
@@ -407,7 +407,7 @@
"primary-key": "0",
}
body := []byte("THE-BODY")
- a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, body, asserts.OpenPGPPrivateKey(testPrivKey1))
+ a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, body, testPrivKey1)
c.Assert(err, IsNil)
c.Check(a.Body(), DeepEquals, body)
@@ -437,7 +437,7 @@
headers["odd"] = "true"
}
- a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, asserts.OpenPGPPrivateKey(testPrivKey1))
+ a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1)
c.Assert(err, IsNil)
decoded, err := asserts.Decode(asserts.Encode(a))
diff -Nru snapd-2.0.5/asserts/crypto.go snapd-2.0.8/asserts/crypto.go
--- snapd-2.0.5/asserts/crypto.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/crypto.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,8 @@
"crypto"
"crypto/rand"
"crypto/rsa"
- _ "crypto/sha256" // be explicit about needing SHA256
+ _ "crypto/sha256" // be explicit about supporting SHA256
+ _ "crypto/sha512" // be explicit about needing SHA512
"encoding/base64"
"encoding/hex"
"fmt"
@@ -82,27 +83,17 @@
return encodeFormatAndData(key.keyFormat(), buf.Bytes()), nil
}
-var openpgpConfig = &packet.Config{
- DefaultHash: crypto.SHA256,
+type openpgpSigner interface {
+ sign(content []byte) (*packet.Signature, error)
}
func signContent(content []byte, privateKey PrivateKey) ([]byte, error) {
- opgPrivKey, ok := privateKey.(openpgpPrivateKey)
+ signer, ok := privateKey.(openpgpSigner)
if !ok {
panic(fmt.Errorf("not an internally supported PrivateKey: %T", privateKey))
}
- privKey := opgPrivKey.privk
-
- sig := new(packet.Signature)
- sig.PubKeyAlgo = privKey.PubKeyAlgo
- sig.Hash = openpgpConfig.Hash()
- sig.CreationTime = time.Now()
- sig.IssuerKeyId = &privKey.KeyId
- h := openpgpConfig.Hash().New()
- h.Write(content)
-
- err := sig.Sign(h, privKey, openpgpConfig)
+ sig, err := signer.sign(content)
if err != nil {
return nil, err
}
@@ -167,7 +158,7 @@
panic(fmt.Errorf("not an internally supported Signature: %T", sig))
}
- h := openpgpConfig.Hash().New()
+ h := opgSig.sig.Hash.New()
h.Write(content)
return pubKey.VerifySignature(h, opgSig.sig)
}
@@ -272,6 +263,29 @@
return opgPrivK.privk.Serialize(w)
}
+var openpgpConfig = &packet.Config{
+ DefaultHash: crypto.SHA512,
+}
+
+func (opgPrivK openpgpPrivateKey) sign(content []byte) (*packet.Signature, error) {
+ privk := opgPrivK.privk
+ sig := new(packet.Signature)
+ sig.PubKeyAlgo = privk.PubKeyAlgo
+ sig.Hash = openpgpConfig.Hash()
+ sig.CreationTime = time.Now()
+ sig.IssuerKeyId = &privk.KeyId
+
+ h := openpgpConfig.Hash().New()
+ h.Write(content)
+
+ err := sig.Sign(h, privk, openpgpConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ return sig, nil
+}
+
func decodePrivateKey(privKey []byte) (PrivateKey, error) {
pkt, err := decodeOpenpgp(privKey, "private key")
if err != nil {
@@ -289,14 +303,123 @@
return openpgpPrivateKey{privk}
}
-func generatePrivateKey() (*packet.PrivateKey, error) {
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
+// GenerateKey generates a private/public key pair.
+func GenerateKey() (PrivateKey, error) {
+ priv, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, err
}
- return packet.NewRSAPrivateKey(time.Now(), priv), nil
+ return OpenPGPPrivateKey(packet.NewRSAPrivateKey(time.Now(), priv)), nil
}
func encodePrivateKey(privKey PrivateKey) ([]byte, error) {
return encodeKey(privKey, "private key")
}
+
+// externally held key pairs
+
+type extPGPPrivateKey struct {
+ pubKey PublicKey
+ from string
+ doSign func(fingerprint string, content []byte) ([]byte, error)
+}
+
+func newExtPGPPrivateKey(exportedPubKeyStream io.Reader, from string, sign func(fingerprint string, content []byte) ([]byte, error)) (PrivateKey, error) {
+ var pubKey *packet.PublicKey
+
+ rd := packet.NewReader(exportedPubKeyStream)
+ for {
+ pkt, err := rd.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, fmt.Errorf("cannot read exported public key: %v", err)
+ }
+ cand, ok := pkt.(*packet.PublicKey)
+ if ok {
+ if cand.IsSubkey {
+ continue
+ }
+ if pubKey != nil {
+ return nil, fmt.Errorf("cannot select exported public key, found many")
+ }
+ pubKey = cand
+ }
+ }
+
+ if pubKey == nil {
+ return nil, fmt.Errorf("cannot read exported public key, found none (broken export)")
+
+ }
+
+ rsaPubKey, ok := pubKey.PublicKey.(*rsa.PublicKey)
+ if !ok {
+ return nil, fmt.Errorf("not a RSA key")
+ }
+
+ bitLen := rsaPubKey.N.BitLen()
+ if bitLen < 4096 {
+ return nil, fmt.Errorf("need at least 4096 bits key, got %d", bitLen)
+ }
+
+ return &extPGPPrivateKey{
+ pubKey: OpenPGPPublicKey(pubKey),
+ from: from,
+ doSign: sign,
+ }, nil
+}
+
+func (expk *extPGPPrivateKey) PublicKey() PublicKey {
+ return expk.pubKey
+}
+
+func (expk *extPGPPrivateKey) keyEncode(w io.Writer) error {
+ return fmt.Errorf("cannot access external private key to encode it")
+}
+
+func (expk *extPGPPrivateKey) keyFormat() string {
+ return ""
+}
+
+func (expk *extPGPPrivateKey) sign(content []byte) (*packet.Signature, error) {
+ out, err := expk.doSign(expk.pubKey.Fingerprint(), content)
+ if err != nil {
+ return nil, err
+ }
+
+ badSig := fmt.Sprintf("bad %s produced signature: ", expk.from)
+
+ sigpkt, err := packet.Read(bytes.NewBuffer(out))
+ if err != nil {
+ return nil, fmt.Errorf(badSig+"%v", err)
+ }
+
+ sig, ok := sigpkt.(*packet.Signature)
+ if !ok {
+ return nil, fmt.Errorf(badSig+"got %T", sigpkt)
+ }
+
+ opgSig := openpgpSignature{sig}
+
+ if sig.IssuerKeyId == nil {
+ return nil, fmt.Errorf(badSig + "no key id in the signature")
+ }
+
+ sigKeyID := opgSig.KeyID()
+ wantedID := expk.pubKey.ID()
+ if sigKeyID != wantedID {
+ return nil, fmt.Errorf(badSig+"wrong key id (expected %q): %s", wantedID, sigKeyID)
+ }
+
+ if sig.Hash != crypto.SHA512 {
+ return nil, fmt.Errorf(badSig + "expected SHA512 digest")
+ }
+
+ err = expk.pubKey.verify(content, opgSig)
+ if err != nil {
+ return nil, fmt.Errorf(badSig+"it does not verify: %v", err)
+ }
+
+ return sig, nil
+}
diff -Nru snapd-2.0.5/asserts/database.go snapd-2.0.8/asserts/database.go
--- snapd-2.0.5/asserts/database.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/database.go 2016-06-08 05:58:01.000000000 +0000
@@ -174,25 +174,6 @@
}, nil
}
-// GenerateKey generates a private/public key pair for identity and
-// stores it returning its key id.
-func (db *Database) GenerateKey(authorityID string) (keyID string, err error) {
- // TODO: optionally delegate the whole thing to the keypair mgr
-
- // TODO: support specifying different key types/algorithms
- privKey, err := generatePrivateKey()
- if err != nil {
- return "", fmt.Errorf("failed to generate private key: %v", err)
- }
-
- pk := OpenPGPPrivateKey(privKey)
- err = db.ImportKey(authorityID, pk)
- if err != nil {
- return "", err
- }
- return pk.PublicKey().ID(), nil
-}
-
// ImportKey stores the given private/public key pair for identity.
func (db *Database) ImportKey(authorityID string, privKey PrivateKey) error {
return db.keypairMgr.Put(authorityID, privKey)
@@ -225,7 +206,7 @@
// Sign assembles an assertion with the provided information and signs it
// with the private key from `headers["authority-id"]` that has the provided key id.
func (db *Database) Sign(assertType *AssertionType, headers map[string]string, body []byte, keyID string) (Assertion, error) {
- authorityID, err := checkMandatory(headers, "authority-id")
+ authorityID, err := checkNotEmpty(headers, "authority-id")
if err != nil {
return nil, err
}
diff -Nru snapd-2.0.5/asserts/database_test.go snapd-2.0.8/asserts/database_test.go
--- snapd-2.0.5/asserts/database_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/database_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -34,8 +34,7 @@
"golang.org/x/crypto/openpgp/packet"
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/asserts"
)
func Test(t *testing.T) { TestingT(t) }
@@ -79,10 +78,10 @@
}
func (dbs *databaseSuite) TestImportKey(c *C) {
- expectedFingerprint := hex.EncodeToString(testPrivKey1.PublicKey.Fingerprint[:])
- expectedKeyID := hex.EncodeToString(testPrivKey1.PublicKey.Fingerprint[12:])
+ expectedFingerprint := hex.EncodeToString(testPrivKey1Pkt.PublicKey.Fingerprint[:])
+ expectedKeyID := hex.EncodeToString(testPrivKey1Pkt.PublicKey.Fingerprint[12:])
- err := dbs.db.ImportKey("account0", asserts.OpenPGPPrivateKey(testPrivKey1))
+ err := dbs.db.ImportKey("account0", testPrivKey1)
c.Assert(err, IsNil)
keyPath := filepath.Join(dbs.topDir, "private-keys-v0/account0", expectedKeyID)
@@ -100,23 +99,15 @@
}
func (dbs *databaseSuite) TestImportKeyAlreadyExists(c *C) {
- err := dbs.db.ImportKey("account0", asserts.OpenPGPPrivateKey(testPrivKey1))
+ err := dbs.db.ImportKey("account0", testPrivKey1)
c.Assert(err, IsNil)
- err = dbs.db.ImportKey("account0", asserts.OpenPGPPrivateKey(testPrivKey1))
+ err = dbs.db.ImportKey("account0", testPrivKey1)
c.Check(err, ErrorMatches, "key pair with given key id already exists")
}
-func (dbs *databaseSuite) TestGenerateKey(c *C) {
- fingerp, err := dbs.db.GenerateKey("account0")
- c.Assert(err, IsNil)
- c.Check(fingerp, NotNil)
- keyPath := filepath.Join(dbs.topDir, "private-keys-v0/account0", fingerp)
- c.Check(osutil.FileExists(keyPath), Equals, true)
-}
-
func (dbs *databaseSuite) TestPublicKey(c *C) {
- pk := asserts.OpenPGPPrivateKey(testPrivKey1)
+ pk := testPrivKey1
fingerp := pk.PublicKey().Fingerprint()
keyid := pk.PublicKey().ID()
err := dbs.db.ImportKey("account0", pk)
@@ -136,21 +127,21 @@
c.Assert(err, IsNil)
pubKey, ok := pkt.(*packet.PublicKey)
c.Assert(ok, Equals, true)
- c.Assert(pubKey.Fingerprint, DeepEquals, testPrivKey1.PublicKey.Fingerprint)
+ c.Assert(pubKey.Fingerprint, DeepEquals, testPrivKey1Pkt.PublicKey.Fingerprint)
}
func (dbs *databaseSuite) TestPublicKeyNotFound(c *C) {
- pk := asserts.OpenPGPPrivateKey(testPrivKey1)
+ pk := testPrivKey1
keyID := pk.PublicKey().ID()
_, err := dbs.db.PublicKey("account0", keyID)
- c.Check(err, ErrorMatches, "no matching key pair found")
+ c.Check(err, ErrorMatches, "cannot find key pair")
err = dbs.db.ImportKey("account0", pk)
c.Assert(err, IsNil)
_, err = dbs.db.PublicKey("account0", "ff"+keyID)
- c.Check(err, ErrorMatches, "no matching key pair found")
+ c.Check(err, ErrorMatches, "cannot find key pair")
}
type checkSuite struct {
@@ -171,7 +162,7 @@
"authority-id": "canonical",
"primary-key": "0",
}
- chks.a, err = asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, asserts.OpenPGPPrivateKey(testPrivKey0))
+ chks.a, err = asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey0)
c.Assert(err, IsNil)
}
@@ -193,7 +184,7 @@
cfg := &asserts.DatabaseConfig{
Backstore: chks.bs,
KeypairManager: asserts.NewMemoryKeypairManager(),
- TrustedKeys: []*asserts.AccountKey{asserts.ExpiredAccountKeyForTest("canonical", &trustedKey.PublicKey)},
+ TrustedKeys: []*asserts.AccountKey{asserts.ExpiredAccountKeyForTest("canonical", trustedKey.PublicKey())},
}
db, err := asserts.OpenDatabase(cfg)
c.Assert(err, IsNil)
@@ -208,7 +199,7 @@
cfg := &asserts.DatabaseConfig{
Backstore: chks.bs,
KeypairManager: asserts.NewMemoryKeypairManager(),
- TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", &trustedKey.PublicKey)},
+ TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
}
db, err := asserts.OpenDatabase(cfg)
c.Assert(err, IsNil)
@@ -217,13 +208,13 @@
content, encodedSig := chks.a.Signature()
// forgery
forgedSig := new(packet.Signature)
- forgedSig.PubKeyAlgo = testPrivKey1.PubKeyAlgo
+ forgedSig.PubKeyAlgo = testPrivKey1Pkt.PubKeyAlgo
forgedSig.Hash = crypto.SHA256
forgedSig.CreationTime = time.Now()
- forgedSig.IssuerKeyId = &testPrivKey0.KeyId
+ forgedSig.IssuerKeyId = &asserts.PrivateKeyPacket(testPrivKey0).KeyId
h := crypto.SHA256.New()
h.Write(content)
- err = forgedSig.Sign(h, testPrivKey1, &packet.Config{DefaultHash: crypto.SHA256})
+ err = forgedSig.Sign(h, testPrivKey1Pkt, &packet.Config{DefaultHash: crypto.SHA256})
c.Assert(err, IsNil)
buf := new(bytes.Buffer)
forgedSig.Serialize(buf)
@@ -254,7 +245,7 @@
c.Assert(err, IsNil)
safs.signingDB = db0
- pk := asserts.OpenPGPPrivateKey(testPrivKey0)
+ pk := testPrivKey0
err = db0.ImportKey("canonical", pk)
c.Assert(err, IsNil)
safs.signingKeyID = pk.PublicKey().ID()
@@ -267,7 +258,7 @@
cfg := &asserts.DatabaseConfig{
Backstore: bs,
KeypairManager: asserts.NewMemoryKeypairManager(),
- TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", &trustedKey.PublicKey)},
+ TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
}
db, err := asserts.OpenDatabase(cfg)
c.Assert(err, IsNil)
@@ -320,7 +311,7 @@
"primary-key": "a",
}
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, "abcd")
- c.Assert(err, ErrorMatches, "no matching key pair found")
+ c.Assert(err, ErrorMatches, "cannot find key pair")
c.Check(a1, IsNil)
}
@@ -499,7 +490,7 @@
}
func (safs *signAddFindSuite) TestFindFindsTrustedAccountKeys(c *C) {
- pk1 := asserts.OpenPGPPrivateKey(testPrivKey1)
+ pk1 := testPrivKey1
pubKey1Encoded, err := asserts.EncodePublicKey(pk1.PublicKey())
c.Assert(err, IsNil)
@@ -584,3 +575,72 @@
c.Check(test.err, ErrorMatches, test.expected)
}
}
+
+type signatureBackwardCompSuite struct{}
+
+var _ = Suite(&signatureBackwardCompSuite{})
+
+func (sbcs *signatureBackwardCompSuite) TestOldSHA256SignaturesWork(c *C) {
+ // these were using SHA256
+
+ const (
+ testTrustedKey = `type: account-key
+authority-id: can0nical
+account-id: can0nical
+public-key-id: 844efa9730eec4be
+public-key-fingerprint: 716ff3cec4b9364a2bd930dc844efa9730eec4be
+since: 2016-01-14T15:00:00Z
+until: 2023-01-14T15:00:00Z
+body-length: 376
+
+openpgp xsBNBFaXv40BCADIlqLKFZaPaoe4TNLQv77vh4JWTlt7Z3IN2ducNqfg50q5mnkyUD2D
+SckvsMy1440+a0Z83m/A7aPaO1JkLpMGfLr23VLyKCaAe0k6hg69/6aEfXhfy0yYvEOgGcBiX+fN
+T6tqdRCsd+08LtisjYez7iJvmVwQ/syeduoTU4EiSVO1zlgc3eeq3TFyvcN0E1EsZ/7l2A33amTo
+mtAPVyQsa1B+lTeaUgwuPBWV0oTuYcUSfYsmmsXEKx/PnzkliicnrC9QZ5CcisskVve3QwPAuLUz
+2nV7/6vSRF22T4cUPF4QntjZBB6xjopdDH6wQsKyzLTTRak74moWksx8MEmVABEBAAE=
+
+openpgp wsBcBAABCAAQBQJWl8DiCRCETvqXMO7EvgAAhjkIAEoINWjQkujtx/TFYsKh0yYcQSpT
+v8O83mLRP7Ty+mH99uQ0/DbeQ1hM5st8cFgzU8SzlDCh6BUMnAl/bR/hhibFD40CBLd13kDXl1aN
+APybmSYoDVRQPAPop44UF0aCrTIw4Xds3E56d2Rsn+CkNML03kRc/i0Q53uYzZwxXVnzW/gVOXDL
+u/IZtjeo3KsB645MVEUxJLQmjlgMOwMvCHJgWhSvZOuf7wC0soBCN9Ufa/0M/PZFXzzn8LpjKVrX
+iDXhV7cY5PceG8ZV7Duo1JadOCzpkOHmai4DcrN7ZeY8bJnuNjOwvTLkrouw9xci4IxpPDRu0T/i
+K9qaJtUo4cA=`
+ testAccKey = `type: account-key
+authority-id: can0nical
+account-id: developer1
+public-key-id: adea89b00094c337
+public-key-fingerprint: 5fa7b16ad5e8c8810d5a0686adea89b00094c337
+since: 2016-01-14T15:00:00Z
+until: 2023-01-14T15:00:00Z
+body-length: 376
+
+openpgp xsBNBFaXv5MBCACkK//qNb3UwRtDviGcCSEi8Z6d5OXok3yilQmEh0LuW6DyP9sVpm08
+Vb1LGewOa5dThWGX4XKRBI/jCUnjCJQ6v15lLwHe1N7MJQ58DUxKqWFMV9yn4RcDPk6LqoFpPGdR
+rbp9Ivo3PqJRMyD0wuJk9RhbaGZmILcL//BLgomE9NgQdAfZbiEnGxtkqAjeVtBtcJIj5TnCC658
+ZCqwugQeO9iJuIn3GosYvvTB6tReq6GP6b4dqvoi7SqxHVhtt2zD4Y6FUZIVmvZK0qwkV0gua2az
+LzPOeoVcU1AEl7HVeBk7G6GiT5jx+CjjoGa0j22LdJB9S3JXHtGYk5p9CAwhABEBAAE=
+
+openpgp wsBcBAABCAAQBQJWl8HNCRCETvqXMO7EvgAAeuAIABn/1i8qGyaIhxOWE2cHIPYW3hq2
+PWpq7qrPN5Dbp/00xrTvc6tvMQWsXlMrAsYuq3sBCxUp3JRp9XhGiQeJtb8ft10g3+3J7e8OGHjl
+CfXJ3A5el8Xxp5qkFywCsLdJgNtF6+uSQ4dO8SrAwzkM7c3JzntxdiFOjDLUSyZ+rXL42jdRagTY
+8bcZfb47vd68Hyz3EvSvJuHSDbcNSTd3B832cimpfq5vJ7FoDrchVn3sg+3IwekuPhG3LQn5BVtc
+0ontHd+V1GaandhqBaDA01cGZN0gnqv2Haogt0P/h3nZZZJ1nTW5PLC6hs8TZdBdl3Lel8yAHD5L
+ZF5jSvRDLgI=`
+ )
+
+ tKey, err := asserts.Decode([]byte(testTrustedKey))
+ c.Assert(err, IsNil)
+
+ cfg := &asserts.DatabaseConfig{
+ KeypairManager: asserts.NewMemoryKeypairManager(),
+ TrustedKeys: []*asserts.AccountKey{tKey.(*asserts.AccountKey)},
+ }
+ db, err := asserts.OpenDatabase(cfg)
+ c.Assert(err, IsNil)
+
+ a, err := asserts.Decode([]byte(testAccKey))
+ c.Assert(err, IsNil)
+
+ err = db.Check(a)
+ c.Check(err, IsNil)
+}
diff -Nru snapd-2.0.5/asserts/device_asserts.go snapd-2.0.8/asserts/device_asserts.go
--- snapd-2.0.5/asserts/device_asserts.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/device_asserts.go 2016-06-08 05:58:01.000000000 +0000
@@ -111,7 +111,7 @@
}
for _, mandatory := range modelMandatory {
- if _, err := checkMandatory(assert.headers, mandatory); err != nil {
+ if _, err := checkNotEmpty(assert.headers, mandatory); err != nil {
return nil, err
}
}
@@ -142,46 +142,46 @@
}, nil
}
-// DeviceSerial holds a device-serial assertion, which is a statement binding a
+// Serial holds a serial assertion, which is a statement binding a
// device identity with the device public key.
-type DeviceSerial struct {
+type Serial struct {
assertionBase
timestamp time.Time
pubKey PublicKey
}
// BrandID returns the brand identifier of the device.
-func (ds *DeviceSerial) BrandID() string {
- return ds.Header("brand-id")
+func (ser *Serial) BrandID() string {
+ return ser.Header("brand-id")
}
// Model returns the model name identifier of the device.
-func (ds *DeviceSerial) Model() string {
- return ds.Header("model")
+func (ser *Serial) Model() string {
+ return ser.Header("model")
}
-// Serial returns the serial of the device, together with brand id and model
-// they form the unique identifier of the device.
-func (ds *DeviceSerial) Serial() string {
- return ds.Header("serial")
+// Serial returns the serial identifier of the device, together with
+// brand id and model they form the unique identifier of the device.
+func (ser *Serial) Serial() string {
+ return ser.Header("serial")
}
// DeviceKey returns the public key of the device.
-func (ds *DeviceSerial) DeviceKey() PublicKey {
- return ds.pubKey
+func (ser *Serial) DeviceKey() PublicKey {
+ return ser.pubKey
}
-// Timestamp returns the time when the device-serial assertion was issued.
-func (ds *DeviceSerial) Timestamp() time.Time {
- return ds.timestamp
+// Timestamp returns the time when the serial assertion was issued.
+func (ser *Serial) Timestamp() time.Time {
+ return ser.timestamp
}
-// TODO: implement further consistency checks for DeviceSerial but first review approach
+// TODO: implement further consistency checks for Serial but first review approach
-func assembleDeviceSerial(assert assertionBase) (Assertion, error) {
+func assembleSerial(assert assertionBase) (Assertion, error) {
// TODO: authority-id can only == canonical or brand-id
- encodedKey, err := checkMandatory(assert.headers, "device-key")
+ encodedKey, err := checkNotEmpty(assert.headers, "device-key")
if err != nil {
return nil, err
}
@@ -196,7 +196,7 @@
}
// ignore extra headers and non-empty body for future compatibility
- return &DeviceSerial{
+ return &Serial{
assertionBase: assert,
timestamp: timestamp,
pubKey: pubKey,
diff -Nru snapd-2.0.5/asserts/device_asserts_test.go snapd-2.0.8/asserts/device_asserts_test.go
--- snapd-2.0.5/asserts/device_asserts_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/device_asserts_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,13 +20,12 @@
package asserts_test
import (
- "fmt"
"strings"
"time"
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
type modelSuite struct {
@@ -35,8 +34,8 @@
}
var (
- _ = Suite(&deviceSerialSuite{})
_ = Suite(&modelSuite{})
+ _ = Suite(&serialSuite{})
)
func (mods *modelSuite) SetUpSuite(c *C) {
@@ -87,25 +86,35 @@
modelErrPrefix = "assertion model: "
)
-func (mods *modelSuite) TestDecodeInvalidMandatory(c *C) {
- encoded := strings.Replace(modelExample, "TSLINE", mods.tsLine, 1)
-
- mandatoryHeaders := []string{"series", "brand-id", "model", "os", "architecture", "gadget", "kernel", "store", "allowed-modes", "required-snaps", "class", "timestamp"}
-
- for _, mandatory := range mandatoryHeaders {
- invalid := strings.Replace(encoded, mandatory+":", "xyz:", 1)
- _, err := asserts.Decode([]byte(invalid))
- c.Check(err, ErrorMatches, fmt.Sprintf("%s%q header is mandatory", modelErrPrefix, mandatory))
- }
-}
-
func (mods *modelSuite) TestDecodeInvalid(c *C) {
encoded := strings.Replace(modelExample, "TSLINE", mods.tsLine, 1)
invalidTests := []struct{ original, invalid, expectedErr string }{
+ {"series: 16\n", "", `"series" header is mandatory`},
+ {"series: 16\n", "series: \n", `"series" header should not be empty`},
+ {"brand-id: brand-id1\n", "", `"brand-id" header is mandatory`},
+ {"brand-id: brand-id1\n", "brand-id: \n", `"brand-id" header should not be empty`},
{"brand-id: brand-id1\n", "brand-id: random\n", `authority-id and brand-id must match, model assertions are expected to be signed by the brand: "brand-id1" != "random"`},
- {"required-snaps: foo, bar\n", "required-snaps: foo,\n", `empty entry in comma separated "required-snaps" header: "foo,"`},
+ {"model: baz-3000\n", "", `"model" header is mandatory`},
+ {"model: baz-3000\n", "model: \n", `"model" header should not be empty`},
+ {"os: core\n", "", `"os" header is mandatory`},
+ {"os: core\n", "os: \n", `"os" header should not be empty`},
+ {"architecture: amd64\n", "", `"architecture" header is mandatory`},
+ {"architecture: amd64\n", "architecture: \n", `"architecture" header should not be empty`},
+ {"gadget: brand-gadget\n", "", `"gadget" header is mandatory`},
+ {"gadget: brand-gadget\n", "gadget: \n", `"gadget" header should not be empty`},
+ {"kernel: baz-linux\n", "", `"kernel" header is mandatory`},
+ {"kernel: baz-linux\n", "kernel: \n", `"kernel" header should not be empty`},
+ {"store: brand-store\n", "", `"store" header is mandatory`},
+ {"store: brand-store\n", "store: \n", `"store" header should not be empty`},
+ {"allowed-modes: \n", "", `"allowed-modes" header is mandatory`},
{"allowed-modes: \n", "allowed-modes: ,\n", `empty entry in comma separated "allowed-modes" header: ","`},
+ {"required-snaps: foo, bar\n", "", `"required-snaps" header is mandatory`},
+ {"required-snaps: foo, bar\n", "required-snaps: foo,\n", `empty entry in comma separated "required-snaps" header: "foo,"`},
+ {"class: fixed\n", "", `"class" header is mandatory`},
+ {"class: fixed\n", "class: \n", `"class" header should not be empty`},
+ {mods.tsLine, "", `"timestamp" header is mandatory`},
+ {mods.tsLine, "timestamp: \n", `"timestamp" header should not be empty`},
{mods.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
}
@@ -146,24 +155,24 @@
c.Assert(err, ErrorMatches, "model assertion timestamp outside of signing key validity")
}
-type deviceSerialSuite struct {
+type serialSuite struct {
ts time.Time
tsLine string
deviceKey asserts.PrivateKey
encodedDevKey string
}
-func (dss *deviceSerialSuite) SetUpSuite(c *C) {
- dss.ts = time.Now().Truncate(time.Second).UTC()
- dss.tsLine = "timestamp: " + dss.ts.Format(time.RFC3339) + "\n"
+func (ss *serialSuite) SetUpSuite(c *C) {
+ ss.ts = time.Now().Truncate(time.Second).UTC()
+ ss.tsLine = "timestamp: " + ss.ts.Format(time.RFC3339) + "\n"
- dss.deviceKey = asserts.OpenPGPPrivateKey(testPrivKey2)
- encodedPubKey, err := asserts.EncodePublicKey(dss.deviceKey.PublicKey())
+ ss.deviceKey = testPrivKey2
+ encodedPubKey, err := asserts.EncodePublicKey(ss.deviceKey.PublicKey())
c.Assert(err, IsNil)
- dss.encodedDevKey = string(encodedPubKey)
+ ss.encodedDevKey = string(encodedPubKey)
}
-const deviceSerialExample = "type: device-serial\n" +
+const serialExample = "type: serial\n" +
"authority-id: canonical\n" +
"brand-id: brand-id1\n" +
"model: baz-3000\n" +
@@ -175,40 +184,48 @@
"\n\n" +
"openpgp c2ln"
-func (dss *deviceSerialSuite) TestDecodeOK(c *C) {
- encoded := strings.Replace(deviceSerialExample, "TSLINE", dss.tsLine, 1)
- encoded = strings.Replace(encoded, "DEVICEKEY", strings.Replace(dss.encodedDevKey, "\n", "\n ", -1), 1)
+func (ss *serialSuite) TestDecodeOK(c *C) {
+ encoded := strings.Replace(serialExample, "TSLINE", ss.tsLine, 1)
+ encoded = strings.Replace(encoded, "DEVICEKEY", strings.Replace(ss.encodedDevKey, "\n", "\n ", -1), 1)
a, err := asserts.Decode([]byte(encoded))
c.Assert(err, IsNil)
- c.Check(a.Type(), Equals, asserts.DeviceSerialType)
- deviceSerial := a.(*asserts.DeviceSerial)
- c.Check(deviceSerial.AuthorityID(), Equals, "canonical")
- c.Check(deviceSerial.Timestamp(), Equals, dss.ts)
- c.Check(deviceSerial.BrandID(), Equals, "brand-id1")
- c.Check(deviceSerial.Model(), Equals, "baz-3000")
- c.Check(deviceSerial.Serial(), Equals, "2700")
- c.Check(deviceSerial.DeviceKey().Fingerprint(), Equals, dss.deviceKey.PublicKey().Fingerprint())
+ c.Check(a.Type(), Equals, asserts.SerialType)
+ serial := a.(*asserts.Serial)
+ c.Check(serial.AuthorityID(), Equals, "canonical")
+ c.Check(serial.Timestamp(), Equals, ss.ts)
+ c.Check(serial.BrandID(), Equals, "brand-id1")
+ c.Check(serial.Model(), Equals, "baz-3000")
+ c.Check(serial.Serial(), Equals, "2700")
+ c.Check(serial.DeviceKey().Fingerprint(), Equals, ss.deviceKey.PublicKey().Fingerprint())
}
const (
- deviceSerialErrPrefix = "assertion device-serial: "
+ serialErrPrefix = "assertion serial: "
)
-func (dss *deviceSerialSuite) TestDecodeInvalid(c *C) {
- encoded := strings.Replace(deviceSerialExample, "TSLINE", dss.tsLine, 1)
+func (ss *serialSuite) TestDecodeInvalid(c *C) {
+ encoded := strings.Replace(serialExample, "TSLINE", ss.tsLine, 1)
invalidTests := []struct{ original, invalid, expectedErr string }{
+ {"brand-id: brand-id1\n", "", `"brand-id" header is mandatory`},
+ {"brand-id: brand-id1\n", "brand-id: \n", `"brand-id" header should not be empty`},
+ {"model: baz-3000\n", "", `"model" header is mandatory`},
+ {"model: baz-3000\n", "model: \n", `"model" header should not be empty`},
{"serial: 2700\n", "", `"serial" header is mandatory`},
+ {"serial: 2700\n", "serial: \n", `"serial" header should not be empty`},
+ {ss.tsLine, "", `"timestamp" header is mandatory`},
+ {ss.tsLine, "timestamp: \n", `"timestamp" header should not be empty`},
+ {ss.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
{"device-key:\n DEVICEKEY\n", "", `"device-key" header is mandatory`},
+ {"device-key:\n DEVICEKEY\n", "device-key: \n", `"device-key" header should not be empty`},
{"device-key:\n DEVICEKEY\n", "device-key: openpgp ZZZ\n", `public key: could not decode base64 data:.*`},
- {dss.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
}
for _, test := range invalidTests {
invalid := strings.Replace(encoded, test.original, test.invalid, 1)
- invalid = strings.Replace(invalid, "DEVICEKEY", strings.Replace(dss.encodedDevKey, "\n", "\n ", -1), 1)
+ invalid = strings.Replace(invalid, "DEVICEKEY", strings.Replace(ss.encodedDevKey, "\n", "\n ", -1), 1)
_, err := asserts.Decode([]byte(invalid))
- c.Check(err, ErrorMatches, deviceSerialErrPrefix+test.expectedErr)
+ c.Check(err, ErrorMatches, serialErrPrefix+test.expectedErr)
}
}
diff -Nru snapd-2.0.5/asserts/digest.go snapd-2.0.8/asserts/digest.go
--- snapd-2.0.5/asserts/digest.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/digest.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,13 +29,13 @@
func EncodeDigest(hash crypto.Hash, hashDigest []byte) (string, error) {
algo := ""
switch hash {
- case crypto.SHA256:
- algo = "sha256"
+ case crypto.SHA512:
+ algo = "sha512"
default:
return "", fmt.Errorf("unsupported hash")
}
if len(hashDigest) != hash.Size() {
return "", fmt.Errorf("hash digest by %s should be %d bytes", algo, hash.Size())
}
- return fmt.Sprintf("%s %s", algo, base64.RawURLEncoding.EncodeToString(hashDigest)), nil
+ return fmt.Sprintf("%s-%s", algo, base64.RawURLEncoding.EncodeToString(hashDigest)), nil
}
diff -Nru snapd-2.0.5/asserts/digest_test.go snapd-2.0.8/asserts/digest_test.go
--- snapd-2.0.5/asserts/digest_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/digest_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
type encodeDigestSuite struct{}
@@ -35,14 +35,14 @@
var _ = Suite(&encodeDigestSuite{})
func (eds *encodeDigestSuite) TestEncodeDigestOK(c *C) {
- h := crypto.SHA256.New()
+ h := crypto.SHA512.New()
h.Write([]byte("some stuff to hash"))
digest := h.Sum(nil)
- encoded, err := asserts.EncodeDigest(crypto.SHA256, digest)
+ encoded, err := asserts.EncodeDigest(crypto.SHA512, digest)
c.Assert(err, IsNil)
- c.Check(strings.HasPrefix(encoded, "sha256 "), Equals, true)
- decoded, err := base64.RawURLEncoding.DecodeString(encoded[len("sha256 "):])
+ c.Check(strings.HasPrefix(encoded, "sha512-"), Equals, true)
+ decoded, err := base64.RawURLEncoding.DecodeString(encoded[len("sha512-"):])
c.Assert(err, IsNil)
c.Check(decoded, DeepEquals, digest)
}
@@ -51,6 +51,6 @@
_, err := asserts.EncodeDigest(crypto.SHA1, nil)
c.Check(err, ErrorMatches, "unsupported hash")
- _, err = asserts.EncodeDigest(crypto.SHA256, []byte{1, 2})
- c.Check(err, ErrorMatches, "hash digest by sha256 should be 32 bytes")
+ _, err = asserts.EncodeDigest(crypto.SHA512, []byte{1, 2})
+ c.Check(err, ErrorMatches, "hash digest by sha512 should be 64 bytes")
}
diff -Nru snapd-2.0.5/asserts/export_test.go snapd-2.0.8/asserts/export_test.go
--- snapd-2.0.5/asserts/export_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/export_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,8 +28,10 @@
// expose test-only things here
-// generatePrivateKey exposed for tests
-var GeneratePrivateKeyInTest = generatePrivateKey
+// access internal openpgp lib packet
+func PrivateKeyPacket(pk PrivateKey) *packet.PrivateKey {
+ return pk.(openpgpPrivateKey).privk
+}
// assembleAndSign exposed for tests
var AssembleAndSignInTest = assembleAndSign
@@ -53,8 +55,7 @@
return enc.append(encoded)
}
-func makeAccountKeyForTest(authorityID string, pubKey *packet.PublicKey, validYears int) *AccountKey {
- openPGPPubKey := OpenPGPPublicKey(pubKey)
+func makeAccountKeyForTest(authorityID string, openPGPPubKey PublicKey, validYears int) *AccountKey {
return &AccountKey{
assertionBase: assertionBase{
headers: map[string]string{
@@ -69,11 +70,11 @@
}
}
-func BootstrapAccountKeyForTest(authorityID string, pubKey *packet.PublicKey) *AccountKey {
+func BootstrapAccountKeyForTest(authorityID string, pubKey PublicKey) *AccountKey {
return makeAccountKeyForTest(authorityID, pubKey, 9999)
}
-func ExpiredAccountKeyForTest(authorityID string, pubKey *packet.PublicKey) *AccountKey {
+func ExpiredAccountKeyForTest(authorityID string, pubKey PublicKey) *AccountKey {
return makeAccountKeyForTest(authorityID, pubKey, 1)
}
@@ -112,3 +113,15 @@
func AccountKeyIsKeyValidAt(ak *AccountKey, when time.Time) bool {
return ak.isKeyValidAt(when)
}
+
+type GPGRunner func(homedir string, input []byte, args ...string) ([]byte, error)
+
+func MockRunGPG(mock func(prev GPGRunner, homedir string, input []byte, args ...string) ([]byte, error)) (restore func()) {
+ prevRunGPG := runGPG
+ runGPG = func(homedir string, input []byte, args ...string) ([]byte, error) {
+ return mock(prevRunGPG, homedir, input, args...)
+ }
+ return func() {
+ runGPG = prevRunGPG
+ }
+}
diff -Nru snapd-2.0.5/asserts/fsbackstore_test.go snapd-2.0.8/asserts/fsbackstore_test.go
--- snapd-2.0.5/asserts/fsbackstore_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/fsbackstore_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
type fsBackstoreSuite struct{}
diff -Nru snapd-2.0.5/asserts/fsentryutils.go snapd-2.0.8/asserts/fsentryutils.go
--- snapd-2.0.5/asserts/fsentryutils.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/fsentryutils.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,7 +25,7 @@
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
// utilities to read/write fs entries
diff -Nru snapd-2.0.5/asserts/fskeypairmgr.go snapd-2.0.8/asserts/fskeypairmgr.go
--- snapd-2.0.5/asserts/fskeypairmgr.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/fskeypairmgr.go 2016-06-08 05:58:01.000000000 +0000
@@ -73,7 +73,7 @@
return nil
}
-var errKeypairNotFound = errors.New("no matching key pair found")
+var errKeypairNotFound = errors.New("cannot find key pair")
func (fskm *filesystemKeypairManager) Get(authorityID, keyID string) (PrivateKey, error) {
fskm.mu.RLock()
diff -Nru snapd-2.0.5/asserts/fskeypairmgr_test.go snapd-2.0.8/asserts/fskeypairmgr_test.go
--- snapd-2.0.5/asserts/fskeypairmgr_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/fskeypairmgr_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
type fsKeypairMgrSuite struct{}
diff -Nru snapd-2.0.5/asserts/gpgkeypairmgr.go snapd-2.0.8/asserts/gpgkeypairmgr.go
--- snapd-2.0.5/asserts/gpgkeypairmgr.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/asserts/gpgkeypairmgr.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,108 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package asserts
+
+import (
+ "bytes"
+ "fmt"
+ "os/exec"
+ "strings"
+)
+
+func runGPGImpl(homedir string, input []byte, args ...string) ([]byte, error) {
+ general := []string{"-q"}
+ if homedir != "" {
+ general = append([]string{"--homedir", homedir}, general...)
+ }
+ allArgs := append(general, args...)
+
+ cmd := exec.Command("gpg", allArgs...)
+ var outBuf bytes.Buffer
+ var errBuf bytes.Buffer
+
+ if len(input) != 0 {
+ cmd.Stdin = bytes.NewBuffer(input)
+ }
+
+ cmd.Stdout = &outBuf
+ cmd.Stderr = &errBuf
+
+ if err := cmd.Run(); err != nil {
+ return nil, fmt.Errorf("gpg %s failed: %v (%q)", strings.Join(args, " "), err, errBuf.Bytes())
+ }
+
+ return outBuf.Bytes(), nil
+}
+
+var runGPG = runGPGImpl
+
+type gpgKeypairManager struct {
+ homedir string
+}
+
+func (gkm *gpgKeypairManager) gpg(input []byte, args ...string) ([]byte, error) {
+ return runGPG(gkm.homedir, input, args...)
+}
+
+// NewGPGKeypairManager creates a new key pair manager backed by a local GnuPG setup
+// using the given GPG homedir, and asking GPG to fallback "~/.gnupg"
+// to default if empty.
+// Importing keys through the keypair manager interface is not
+// suppored.
+// Main purpose is allowing signing using keys from a GPG setup.
+func NewGPGKeypairManager(homedir string) KeypairManager {
+ return &gpgKeypairManager{
+ homedir: homedir,
+ }
+}
+
+func (gkm *gpgKeypairManager) Put(authorityID string, privKey PrivateKey) error {
+ // NOTE: we don't need this initially at least and this keypair mgr is not for general arbitrary usage
+ return fmt.Errorf("cannot import private key into GPG keyring")
+}
+
+func (gkm *gpgKeypairManager) Get(authorityID, keyID string) (PrivateKey, error) {
+ out, err := gkm.gpg(nil, "--batch", "--export", "--export-options", "export-minimal,export-clean,no-export-attributes", "0x"+keyID)
+ if err != nil {
+ return nil, err
+ }
+ if len(out) == 0 {
+ return nil, fmt.Errorf("cannot find key %q in GPG keyring", keyID)
+ }
+
+ pubKeyBuf := bytes.NewBuffer(out)
+ privKey, err := newExtPGPPrivateKey(pubKeyBuf, "GPG", gkm.sign)
+ if err != nil {
+ return nil, fmt.Errorf("cannot use GPG key %q: %v", keyID, err)
+ }
+ gotID := privKey.PublicKey().ID()
+ if gotID != keyID {
+ return nil, fmt.Errorf("got wrong key from GPG, expected %q: %s", keyID, gotID)
+ }
+ return privKey, nil
+}
+
+func (gkm *gpgKeypairManager) sign(fingerprint string, content []byte) ([]byte, error) {
+ out, err := gkm.gpg(content, "--personal-digest-preferences", "SHA512", "--default-key", "0x"+fingerprint, "--detach-sign")
+ if err != nil {
+ return nil, fmt.Errorf("cannot sign using GPG: %v", err)
+ }
+ return out, nil
+}
diff -Nru snapd-2.0.5/asserts/gpgkeypairmgr_test.go snapd-2.0.8/asserts/gpgkeypairmgr_test.go
--- snapd-2.0.5/asserts/gpgkeypairmgr_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/asserts/gpgkeypairmgr_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,410 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package asserts_test
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+ "fmt"
+ "os/exec"
+ "regexp"
+ "time"
+
+ . "gopkg.in/check.v1"
+
+ "golang.org/x/crypto/openpgp/armor"
+ "golang.org/x/crypto/openpgp/packet"
+
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/osutil"
+)
+
+type gpgKeypairMgrSuite struct {
+ homedir string
+ keypairMgr asserts.KeypairManager
+}
+
+var _ = Suite(&gpgKeypairMgrSuite{})
+
+func (gkms *gpgKeypairMgrSuite) SetUpSuite(c *C) {
+ if !osutil.FileExists("/usr/bin/gpg") {
+ c.Skip("gpg not installed")
+ }
+}
+
+const (
+ testKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQcYBFdLWPQBEAC4GPsC/slzwiuJDVVVfEAyTt/Pwn+TEvGuHUr0fVzT+wld66CN
+ZHGIx2q9h3ai58M33CpsCsILJaIt5BrQC7DGSiyx7KG7SWkZ0HsXF1qUmiWK4PIk
+QgTphXC+Q2WuTWpXXmyaN8/bHcKir3vj5b7JP1rHL95whRj3WCdAqgCxI31mIqp3
+ecdNHSztRCDCVtFBxULY9BzyIYtw26b2COZtuHMuhsJZll72+qQj+zc+L/T61706
+LSC21DI/sEqTk97IC9BEhgKbGxITY9Bt2PezbsjflHtesbCWI5E5T3OpUHCQhZli
+9I/xsFtk9SIrxaCAqFlOQbf4MK/W+je7BGsOZfXWzoNWxOWbCjV+4YSt4a8xuULK
+oJe/heAQySwn4s5qQaTK8Xr5Z2XTQ20q8GZ/gJ1p5JQXMxON//UbPKwH1cWwfIMj
+Y9WZIw2Pcn+c3fWc5aI3Czpzq8T5RmaE1qdGx+MBLlLBXLKPVwSZlZoDeW5vzmIR
+R/tNYUzSNeU62NFoAH6myl7wo7u9dgj//VSBPXrZumqQnWsLXdv2E2n6eQ3DQUX0
+NqWUSs0jVoqGfByfc7NliYq1y8Nn+TnuTwcGfyyjfFbGhFeSXYRn+1/pLLLtsetb
+v56/cNMwbJrO2xaBFBFObzz3jgF2ntrgM8usAWvLI3mbWEoBPYVppz80QwARAQAB
+AA/8CNHq5hFWjc0N2z1AIIjZOy/L3unMGpFBR/IPqcKpzwl2FkGtiaiixzFP/AWV
+7vxt6MALvkJjr+IH25f+mty8hZDUhFpjGJR4ocElweJKDNg3wpLADHGnR5gvjHCx
+L0EhPk9VTQGDMVXDLJp+CS9Jd93TrRBY4V4sZzPvftRw6mEEvH8eWKavyueCGVn2
+vH4pUgkv3dy62Eo4IoTmLQpvHm7vAcR4t48R51ZJxTmKGNjLrWA8U3cJsV4INu9C
+G2uYXvrbPwqGlxocaxZl9s/6yhDINJdUs8w35XGNycefMcubS6lC7dqWsjccodZx
+Yn8k5JUW4OjFdhwVs0B9/rVEUFxJtQ6t28bl4qAGZaXgU4z4lj1zUcOFf3jQdfu8
+uePfo9Ts8o2B6HaF4nInxCVZzHACy3Xk8/Kl7Qv8UJcfzaJto0v7p6V9BfHji3kg
+pOuxoSzhOl0EOD93XHhM1J0CaYTB2AmErAktHiSS7QolEEfJS4OrX6LBMOF6NwDG
+rdX6H/hsO2qeF48s1tpPw0gTa4+awdsQYFwBjFBHWqOROrjr+d3S3iRsKafjXoEG
+wGnBZ3VeTqlhylp9v+A7qx1A7H62Fyf8kJn1sXi209hs9y+83icL4iP9j2BbLVoe
+a0Fn8bNvBhJBwLBfibUgM2LWnIzU0/sVaX4Yk3ni1fX5GG0IAM7aqKVi5IVN2mlW
+2MFWaH8wmML6r/EpXYHhY8lAj9BWBlkQZqoMe2g+CbNol0nLNf/B24qHsSv0JXBI
+TWxBt2UtJiHx9plaQLYT1O+FYl2zHU90GTxKqmv6SmR8oKk4bOG7g4hoXMdLAgWt
+CUrjTgG3HUk7Wg+ZGvKyx53CMYXao2lWxWYnWNhX3n17ulqWtPEKzPFcYnJbBIDK
+9V9swkOIV0yMxnMWtxIGKeG2IfnCTl5z3qROzFRGvYEkT5zJrcWxekSDkAiZoXRT
+e4JMQDmI9rdnXZ8HybcAv1noYlxDIRuHPB0jp4X1GROaG2zcruVhPoxa4uT5FV+3
+K+jpurcIAOPWN002QotWWPdtxBgOhReU6CClk/OOzm3UgzYi4Gk0kLSe0Ozn8B8P
+kxhkRZ08HVdydl2aKBFu7Y/1RFq+o5WoVukCWIWPG+h/stHkTkk1EdesL/hjsN6H
+DoVnT0i7HAIsC9bb7hL+WTPZQoDsuwYs3k+zsEQSDXhkN7W+5CVZdE3Cc/IY8wWO
+/+lZoHoDR7lThEJl+G8YiNdb6T3YUNxH3jMzBN1ydQS64CYdqySzK5UxSIxMjXz3
+7Ww0RnFx6kN0g2ae3IlxUbmse2ugLETzX7ABTqbDVpgJLJMkyLk21h9DRfnlAAKY
+IjAsrvNCsQDON2w3F7iZlqrj2Kh99tUH/2Z27+sNrOEVUjMf+Ds9RrKOkrUMcNWe
+l1dM0UAHMOpBew9qimdXwI7lrH6SW4k4QEDdWBHhPOUVYqj2F+i+8sZwgqhmDwsw
+2R3oPLP/pGrQRK2jjLNRztvgy22ASrYYHZd/WkUjBNHRVTXJYArGrvbz3KbhCe3N
+b9Z/CJSx1zeiTRrJSzTxTIlsJGEw06WtAy7bSeXeOo3rD0yUPmP/GLKfIUfxUHkV
+f+u5vm6XVbDf0kp3ZgDWjFtEJNWNajDOI3xA8dv5yXUnQYRLluo33QEZVYg5S+LK
+p9lTBrkp/u8st5Mwzq1ptm45SgmnrT0vsf8kiaB6uE9wuSVE3009+suAuLQHICh0
+ZXN0KYkCOAQTAQgAIgUCV0tY9AIbLwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
+CgkQtSz0OKLQePc2IxAAheBE2JTGZlxgPn88zc3BlDeqh89ZeQ5Kl7qz1dU/DpiQ
+Wf1cNaV9bf+3bczWtcRHFjREVEj3MR7d8WulRz2br5zB1thGt1h1ayfT5c+W/AM1
+I/VgC/SFdKN6pk1fJjDc9qrJn86pOexAHNHyPwTAxnlQ3t4Q9OzOuHTDBuLvWkzz
+rlWAYFqBiYlnRBa3v0De1dKpYl5mbv/N1co9neyl8EsfL9AyBUv42j8OYBb3mAYF
+mrG2KObUib7zYeJ+M1d1VMkBZUSw2ZWStseHxo42S3c5teHQwnYSfHznTL/fibLA
+OreGNemvTCbWVuZfLYGt1yRjrDP2uBpdH3bq/uLtdhvXzeTc2Hs86mYa9+gJgkXC
+XwnJ41Hw+dRoSsoUOc4WQALBT9BsEuK3MzXj11Wyg3QwLiyF2Tr72mzVKvZO/GRy
+jBvmEimoevu0RB9MlDB7c01B34sBQ0R+GhKyQxxC0cstKGoi/8wF1O3HmbrbjiRk
+grX5x90vvu5HJHR1Pjpi/9FDj8nm7gKZ+pGYqmYvzLU8hOy6WiQObiRid56uQem6
+ECfMJlWnQtzAUVTBrtckGSzlKhO6laLiR9Bg90uCzKjYehW6PCVpMp2vmEsqo0r0
+n/YBufIZs9/L1Gblpi0SL6ZTjZdQ2Wj8btU+OlWiJM3LNIMJAZRtMRBfmljnijQ=
+=r01O
+-----END PGP PRIVATE KEY BLOCK-----
+`
+
+ testKeyID = "b52cf438a2d078f7"
+
+ testKeyFingerprint = "42a3050d365c10d5c093abeeb52cf438a2d078f7"
+)
+
+func (gkms *gpgKeypairMgrSuite) importKey(c *C, key string) {
+ gpg := exec.Command("gpg", "--homedir", gkms.homedir, "-q", "--batch", "--import", "--armor")
+ gpg.Stdin = bytes.NewBufferString(key)
+ out, err := gpg.CombinedOutput()
+ c.Assert(err, IsNil, Commentf("test key import failed: %v (%q)", err, out))
+}
+
+func (gkms *gpgKeypairMgrSuite) SetUpTest(c *C) {
+ gkms.homedir = c.MkDir()
+ gkms.keypairMgr = asserts.NewGPGKeypairManager(gkms.homedir)
+ // import test key
+ gkms.importKey(c, testKey)
+}
+
+func (gkms *gpgKeypairMgrSuite) TestGetPublicKeyLooksGood(c *C) {
+ got, err := gkms.keypairMgr.Get("auth-id1", testKeyID)
+ c.Assert(err, IsNil)
+ fp := got.PublicKey().Fingerprint()
+ c.Check(fp, Equals, testKeyFingerprint)
+}
+
+func (gkms *gpgKeypairMgrSuite) TestGetNotFound(c *C) {
+ got, err := gkms.keypairMgr.Get("auth-id1", "ffffffffffffffff")
+ c.Check(err, ErrorMatches, `cannot find key "ffffffffffffffff" in GPG keyring`)
+ c.Check(got, IsNil)
+}
+
+func (gkms *gpgKeypairMgrSuite) TestUseInSigning(c *C) {
+ trustedKey, err := asserts.GenerateKey()
+ c.Assert(err, IsNil)
+
+ tmgr := asserts.NewMemoryKeypairManager()
+ tmgr.Put("trusted", trustedKey)
+
+ authorityDB, err := asserts.OpenDatabase(&asserts.DatabaseConfig{
+ KeypairManager: tmgr,
+ })
+ c.Assert(err, IsNil)
+
+ now := time.Now().UTC()
+ headers := map[string]string{
+ "authority-id": "trusted",
+ "account-id": "trusted",
+ "public-key-id": trustedKey.PublicKey().ID(),
+ "public-key-fingerprint": trustedKey.PublicKey().Fingerprint(),
+ "since": now.Format(time.RFC3339),
+ "until": now.AddDate(10, 0, 0).Format(time.RFC3339),
+ }
+ pubTrustedKeyEnc, err := asserts.EncodePublicKey(trustedKey.PublicKey())
+ c.Assert(err, IsNil)
+ trustedAccKey, err := authorityDB.Sign(asserts.AccountKeyType, headers, pubTrustedKeyEnc, trustedKey.PublicKey().ID())
+ c.Assert(err, IsNil)
+
+ devKey, err := gkms.keypairMgr.Get("dev1", testKeyID)
+ c.Assert(err, IsNil)
+ headers = map[string]string{
+ "authority-id": "trusted",
+ "account-id": "dev1-id",
+ "public-key-id": devKey.PublicKey().ID(),
+ "public-key-fingerprint": devKey.PublicKey().Fingerprint(),
+ "since": now.Format(time.RFC3339),
+ "until": now.AddDate(10, 0, 0).Format(time.RFC3339),
+ }
+ pubDevKeyEnc, err := asserts.EncodePublicKey(devKey.PublicKey())
+ c.Assert(err, IsNil)
+ devAccKey, err := authorityDB.Sign(asserts.AccountKeyType, headers, pubDevKeyEnc, trustedKey.PublicKey().ID())
+ c.Assert(err, IsNil)
+
+ signDB, err := asserts.OpenDatabase(&asserts.DatabaseConfig{
+ KeypairManager: gkms.keypairMgr,
+ })
+ c.Assert(err, IsNil)
+
+ checkDB, err := asserts.OpenDatabase(&asserts.DatabaseConfig{
+ KeypairManager: asserts.NewMemoryKeypairManager(),
+ Backstore: asserts.NewMemoryBackstore(),
+ TrustedKeys: []*asserts.AccountKey{trustedAccKey.(*asserts.AccountKey)},
+ })
+ c.Assert(err, IsNil)
+ err = checkDB.Add(devAccKey)
+ c.Assert(err, IsNil)
+
+ headers = map[string]string{
+ "authority-id": "dev1-id",
+ "series": "16",
+ "snap-id": "snap-id-1",
+ "snap-digest": "sha512-...",
+ "grade": "devel",
+ "snap-size": "1025",
+ "timestamp": now.Format(time.RFC3339),
+ }
+ snapBuild, err := signDB.Sign(asserts.SnapBuildType, headers, nil, testKeyID)
+ c.Assert(err, IsNil)
+
+ err = checkDB.Check(snapBuild)
+ c.Check(err, IsNil)
+}
+
+const (
+ dsaKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQNTBFdLWt0RCAC3sBvyl2j13gKxvnRF7DpBfN1cxba8n/qvCu2uGvlaekCFCVol
+jJt594gL0QRzWPaV+KWQQroZ4u0knYA15QCbFqJ/ziX7zRI+5xcOGJ8ZBJJnDiGM
+Eu7v2NGpxJHxgz1n+fjUqDPC/fHMfnQ1bkYNbXDXht2Uw9j8LP3FPueYRH46ZYQs
+G91s6x+row7RCIGJcg0gVJhVvqoojk+Z+7pQ2kiNIeBeVztjybZGLlqL6fnKfeXq
+TsBjnsqUIxdu286UU/xkn6sHa4APqr5wywNjvWoRyWIXxQVTWQp81PlvPfJFyCJJ
+diOb6z2+sfbQ+jdB/MUXYAT2HaOhRMaP/9UPAQCr/nhHyDBb5iq1F/YdftulV9wx
+cOGdWxM2AD9LnLLHGQf+Oct7QLco7SK43NzIDNvp1J/ESK6smfsIgMz6ICyj1Z21
+8Rch0do/0fAiKQpAimxvMQnSE4JtT92xPPV0PdHde/Xs8QxoaKnF2XECoIqMFmjP
+VLerqhyWOv3CE+MHLbj0b0WMl5DSYAcizgF6768R8To9Oow/YdEy7GFCutPoFlNE
+EHW+FA0EZVwGi3BelWMEAjJS+EtJ8knP9d7Im+GHBZ41f0yWU06CWgncfQvxxrOw
+9f/uO2eoTpSb4QLqyasnp4e93iul1r1sJuGYFscQUo1gXJWvGJyh+iYj/K+bk53Y
+fbbc4efJOLNJ6blBLFRY1cwFWKKEmn+GtsN7TA88lAf+MOnzlSpEDMMNHSPcU/RI
+KJe2VDuf3z7nP6Isy9PbPLtuXothU0iLtR76SZuVkUMtRDf+s2B79Lb5c4LQhg8H
+DAiuJqUtCUmyAwwHj2cv5rZT3YuOOb80D16rHXM4Ut05oYeGNEulHG2Qsqe6pxUp
+gEL7Ar2ZempjeVpN8jNqbOW8WHsYJ49CHA6pF30hGIHk2zMvBKBORa5kGEpgSDex
+kZWB66bOXveUpharOwsvnaa/9SLL+DLcdaVUydrGZMPNVTmoXQmJpvNZj+7uU8IU
+RYDEoe9lalEwXUv7Z2eAbMbo23AYKN4omxuaW9cp/hldiXoHgh70KGuwlBtSd+ml
+bAAA/jFnXDTFL0rDbz9ykVftBS/QooNR2xZLam/0G824RpQKDyO0BiAoZHNhKYh6
+BBMRCAAiBQJXS1rdAhsjBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBWv9KR
+5/7U5VSKAQCSrbnVtHaGN9ZUk/PtnJMhbBTtk2R2Y4huxCdFUYQc0QD+IxU66SP+
+Iri22tgdp1HhmTuG2ZyaxUs0cDgkzRTrsAg=
+=Pbfn
+-----END PGP PRIVATE KEY BLOCK-----
+`
+
+ dsaKeyID = "56bfd291e7fed4e5"
+)
+
+func (gkms *gpgKeypairMgrSuite) TestGetWrongKeyType(c *C) {
+ gkms.importKey(c, dsaKey)
+ _, err := gkms.keypairMgr.Get("auth-id1", dsaKeyID)
+ c.Check(err, ErrorMatches, fmt.Sprintf(`cannot use GPG key %q: not a RSA key`, dsaKeyID))
+}
+
+func (gkms *gpgKeypairMgrSuite) TestGetNotUnique(c *C) {
+ mockGPG := func(prev asserts.GPGRunner, homedir string, input []byte, args ...string) ([]byte, error) {
+ c.Assert(args[1], Equals, "--export")
+
+ pk1, err := rsa.GenerateKey(rand.Reader, 512)
+ c.Assert(err, IsNil)
+ pk2, err := rsa.GenerateKey(rand.Reader, 512)
+ c.Assert(err, IsNil)
+
+ buf := new(bytes.Buffer)
+ err = packet.NewRSAPublicKey(time.Now(), &pk1.PublicKey).Serialize(buf)
+ c.Assert(err, IsNil)
+ err = packet.NewRSAPublicKey(time.Now(), &pk2.PublicKey).Serialize(buf)
+ c.Assert(err, IsNil)
+
+ return buf.Bytes(), nil
+ }
+ restore := asserts.MockRunGPG(mockGPG)
+ defer restore()
+
+ _, err := gkms.keypairMgr.Get("auth-id1", testKeyID)
+ c.Check(err, ErrorMatches, fmt.Sprintf("cannot use GPG key %q: cannot select exported public key, found many", testKeyID))
+}
+
+func (gkms *gpgKeypairMgrSuite) TestGetWrongKeyLength(c *C) {
+ mockGPG := func(prev asserts.GPGRunner, homedir string, input []byte, args ...string) ([]byte, error) {
+ c.Assert(args[1], Equals, "--export")
+
+ pk, err := rsa.GenerateKey(rand.Reader, 512)
+ c.Assert(err, IsNil)
+ pubPkt := packet.NewRSAPublicKey(time.Now(), &pk.PublicKey)
+ buf := new(bytes.Buffer)
+ err = pubPkt.Serialize(buf)
+ c.Assert(err, IsNil)
+ return buf.Bytes(), nil
+ }
+ restore := asserts.MockRunGPG(mockGPG)
+ defer restore()
+
+ _, err := gkms.keypairMgr.Get("auth-id1", testKeyID)
+ c.Check(err, ErrorMatches, fmt.Sprintf("cannot use GPG key %q: need at least 4096 bits key, got 512", testKeyID))
+}
+
+func (gkms *gpgKeypairMgrSuite) TestUseInSigningBrokenSignature(c *C) {
+ blk, err := armor.Decode(bytes.NewBuffer([]byte(testKey)))
+ c.Assert(err, IsNil)
+ pkPkt, err := packet.Read(blk.Body)
+ c.Assert(err, IsNil)
+ privk, ok := pkPkt.(*packet.PrivateKey)
+ c.Assert(ok, Equals, true)
+
+ var breakSig func(sig *packet.Signature, cont []byte) []byte
+
+ mockGPG := func(prev asserts.GPGRunner, homedir string, input []byte, args ...string) ([]byte, error) {
+ if args[1] == "--export" {
+ return prev(homedir, input, args...)
+ }
+ n := len(args)
+ c.Assert(args[n-1], Equals, "--detach-sign")
+
+ sig := new(packet.Signature)
+ sig.PubKeyAlgo = packet.PubKeyAlgoRSA
+ sig.Hash = crypto.SHA512
+ sig.CreationTime = time.Now()
+ sig.IssuerKeyId = &privk.KeyId
+
+ // poking to break the signature
+ cont := breakSig(sig, input)
+
+ h := sig.Hash.New()
+ h.Write([]byte(cont))
+
+ err := sig.Sign(h, privk, nil)
+ c.Assert(err, IsNil)
+
+ buf := new(bytes.Buffer)
+ sig.Serialize(buf)
+ return buf.Bytes(), nil
+ }
+ restore := asserts.MockRunGPG(mockGPG)
+ defer restore()
+
+ signDB, err := asserts.OpenDatabase(&asserts.DatabaseConfig{
+ KeypairManager: gkms.keypairMgr,
+ })
+ c.Assert(err, IsNil)
+
+ headers := map[string]string{
+ "authority-id": "dev1-id",
+ "series": "16",
+ "snap-id": "snap-id-1",
+ "snap-digest": "sha512-...",
+ "grade": "devel",
+ "snap-size": "1025",
+ "timestamp": time.Now().Format(time.RFC3339),
+ }
+
+ tests := []struct {
+ breakSig func(*packet.Signature, []byte) []byte
+ expectedErr string
+ }{
+ {func(sig *packet.Signature, cont []byte) []byte {
+ sig.Hash = crypto.SHA1
+ return cont
+ }, "cannot sign assertion: bad GPG produced signature: expected SHA512 digest"},
+ {func(sig *packet.Signature, cont []byte) []byte {
+ sig.IssuerKeyId = nil
+ return cont
+ }, "cannot sign assertion: bad GPG produced signature: no key id in the signature"},
+ {func(sig *packet.Signature, cont []byte) []byte {
+ sig.IssuerKeyId = new(uint64)
+ *sig.IssuerKeyId = 0xffffffffffffffff
+ return cont
+ }, regexp.QuoteMeta(fmt.Sprintf("cannot sign assertion: bad GPG produced signature: wrong key id (expected %q): ffffffffffffffff", testKeyID))},
+ {func(sig *packet.Signature, cont []byte) []byte {
+ return cont[:5]
+ }, "cannot sign assertion: bad GPG produced signature: it does not verify:.*"},
+ }
+
+ for _, t := range tests {
+ breakSig = t.breakSig
+
+ _, err = signDB.Sign(asserts.SnapBuildType, headers, nil, testKeyID)
+ c.Check(err, ErrorMatches, t.expectedErr)
+ }
+
+}
+
+func (gkms *gpgKeypairMgrSuite) TestUseInSigningFailure(c *C) {
+ mockGPG := func(prev asserts.GPGRunner, homedir string, input []byte, args ...string) ([]byte, error) {
+ if args[1] == "--export" {
+ return prev(homedir, input, args...)
+ }
+ n := len(args)
+ c.Assert(args[n-1], Equals, "--detach-sign")
+ return nil, fmt.Errorf("boom")
+ }
+ restore := asserts.MockRunGPG(mockGPG)
+ defer restore()
+
+ signDB, err := asserts.OpenDatabase(&asserts.DatabaseConfig{
+ KeypairManager: gkms.keypairMgr,
+ })
+ c.Assert(err, IsNil)
+
+ headers := map[string]string{
+ "authority-id": "dev1-id",
+ "series": "16",
+ "snap-id": "snap-id-1",
+ "snap-digest": "sha512-...",
+ "grade": "devel",
+ "snap-size": "1025",
+ "timestamp": time.Now().Format(time.RFC3339),
+ }
+
+ _, err = signDB.Sign(asserts.SnapBuildType, headers, nil, testKeyID)
+ c.Check(err, ErrorMatches, "cannot sign assertion: cannot sign using GPG: boom")
+}
diff -Nru snapd-2.0.5/asserts/header_checks.go snapd-2.0.8/asserts/header_checks.go
--- snapd-2.0.5/asserts/header_checks.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/header_checks.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,11 +28,19 @@
// common checks used when decoding/assembling assertions
-func checkMandatory(headers map[string]string, name string) (string, error) {
+func checkExists(headers map[string]string, name string) (string, error) {
value, ok := headers[name]
if !ok {
return "", fmt.Errorf("%q header is mandatory", name)
}
+ return value, nil
+}
+
+func checkNotEmpty(headers map[string]string, name string) (string, error) {
+ value, err := checkExists(headers, name)
+ if err != nil {
+ return "", err
+ }
if len(value) == 0 {
return "", fmt.Errorf("%q header should not be empty", name)
}
@@ -70,7 +78,7 @@
}
func checkRFC3339Date(headers map[string]string, name string) (time.Time, error) {
- dateStr, err := checkMandatory(headers, name)
+ dateStr, err := checkNotEmpty(headers, name)
if err != nil {
return time.Time{}, err
}
@@ -82,7 +90,7 @@
}
func checkUint(headers map[string]string, name string, bitSize int) (uint64, error) {
- valueStr, err := checkMandatory(headers, name)
+ valueStr, err := checkNotEmpty(headers, name)
if err != nil {
return 0, err
}
diff -Nru snapd-2.0.5/asserts/identity.go snapd-2.0.8/asserts/identity.go
--- snapd-2.0.5/asserts/identity.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/identity.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,78 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-
-/*
- * Copyright (C) 2016 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package asserts
-
-import "time"
-
-var (
- identityValidationCertified = "certified"
-)
-
-// Identity holds an identity assertion, which provides a name for an account
-// and the authority's confidence in the name's validity.
-type Identity struct {
- assertionBase
- certified bool
- timestamp time.Time
-}
-
-// AccountID returns the account-id of the identit.
-func (id *Identity) AccountID() string {
- return id.Header("account-id")
-}
-
-// DisplayName returns the human-friendly name for the identity.
-func (id *Identity) DisplayName() string {
- return id.Header("display-name")
-}
-
-// IsCertified returns true if the authority has confidence in the identity's name.
-func (id *Identity) IsCertified() bool {
- return id.certified
-}
-
-// Timestamp returns the time when the identity was issued.
-func (id *Identity) Timestamp() time.Time {
- return id.timestamp
-}
-
-func assembleIdentity(assert assertionBase) (Assertion, error) {
- _, err := checkMandatory(assert.headers, "display-name")
- if err != nil {
- return nil, err
- }
-
- _, err = checkMandatory(assert.headers, "validation")
- if err != nil {
- return nil, err
- }
- certified := assert.headers["validation"] == identityValidationCertified
-
- timestamp, err := checkRFC3339Date(assert.headers, "timestamp")
- if err != nil {
- return nil, err
- }
-
- return &Identity{
- assertionBase: assert,
- certified: certified,
- timestamp: timestamp,
- }, nil
-}
diff -Nru snapd-2.0.5/asserts/identity_test.go snapd-2.0.8/asserts/identity_test.go
--- snapd-2.0.5/asserts/identity_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/identity_test.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,127 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-
-/*
- * Copyright (C) 2016 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package asserts_test
-
-import (
- "fmt"
- "strings"
- "time"
-
- "github.com/ubuntu-core/snappy/asserts"
- . "gopkg.in/check.v1"
-)
-
-var (
- _ = Suite(&identitySuite{})
-)
-
-type identitySuite struct {
- ts time.Time
- tsLine string
-}
-
-func (ids *identitySuite) SetUpSuite(c *C) {
- ids.ts = time.Now().Truncate(time.Second).UTC()
- ids.tsLine = "timestamp: " + ids.ts.Format(time.RFC3339) + "\n"
-}
-
-const identityExample = "type: identity\n" +
- "authority-id: canonical\n" +
- "account-id: abc-123\n" +
- "display-name: Display Name\n" +
- "validation: certified\n" +
- "TSLINE" +
- "body-length: 0" +
- "\n\n" +
- "openpgp c2ln"
-
-func (ids *identitySuite) TestDecodeOK(c *C) {
- encoded := strings.Replace(identityExample, "TSLINE", ids.tsLine, 1)
- a, err := asserts.Decode([]byte(encoded))
- c.Assert(err, IsNil)
- c.Check(a.Type(), Equals, asserts.IdentityType)
- identity := a.(*asserts.Identity)
- c.Check(identity.AuthorityID(), Equals, "canonical")
- c.Check(identity.Timestamp(), Equals, ids.ts)
- c.Check(identity.AccountID(), Equals, "abc-123")
- c.Check(identity.DisplayName(), Equals, "Display Name")
- c.Check(identity.IsCertified(), Equals, true)
-}
-
-func (ids *identitySuite) TestIsCertified(c *C) {
- tests := []struct {
- value string
- isCertified bool
- }{
- {"certified", true},
- {"unproven", false},
- {"nonsense", false},
- }
-
- template := strings.Replace(identityExample, "TSLINE", ids.tsLine, 1)
- for _, test := range tests {
- encoded := strings.Replace(
- template,
- "validation: certified\n",
- fmt.Sprintf("validation: %s\n", test.value),
- 1,
- )
- assert, err := asserts.Decode([]byte(encoded))
- c.Assert(err, IsNil)
- identity := assert.(*asserts.Identity)
- c.Check(identity.IsCertified(), Equals, test.isCertified)
- }
-}
-
-const (
- identityErrPrefix = "assertion identity: "
-)
-
-func (ids *identitySuite) TestDecodeInvalid(c *C) {
- encoded := strings.Replace(identityExample, "TSLINE", ids.tsLine, 1)
-
- invalidTests := []struct{ original, invalid, expectedErr string }{
- {"account-id: abc-123\n", "", `"account-id" header is mandatory`},
- {"display-name: Display Name\n", "", `"display-name" header is mandatory`},
- {"validation: certified\n", "", `"validation" header is mandatory`},
- {ids.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
- }
-
- for _, test := range invalidTests {
- invalid := strings.Replace(encoded, test.original, test.invalid, 1)
- _, err := asserts.Decode([]byte(invalid))
- c.Check(err, ErrorMatches, identityErrPrefix+test.expectedErr)
- }
-}
-
-func (ids *identitySuite) TestCheckInconsistentTimestamp(c *C) {
- ex, err := asserts.Decode([]byte(strings.Replace(identityExample, "TSLINE", ids.tsLine, 1)))
- c.Assert(err, IsNil)
-
- signingKeyID, accSignDB, db := makeSignAndCheckDbWithAccountKey(c, "canonical")
-
- headers := ex.Headers()
- headers["timestamp"] = "2011-01-01T14:00:00Z"
- identity, err := accSignDB.Sign(asserts.IdentityType, headers, nil, signingKeyID)
- c.Assert(err, IsNil)
-
- err = db.Check(identity)
- c.Assert(err, ErrorMatches, "identity assertion timestamp outside of signing key validity")
-}
diff -Nru snapd-2.0.5/asserts/membackstore_test.go snapd-2.0.8/asserts/membackstore_test.go
--- snapd-2.0.5/asserts/membackstore_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/membackstore_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
type memBackstoreSuite struct {
diff -Nru snapd-2.0.5/asserts/memkeypairmgr_test.go snapd-2.0.8/asserts/memkeypairmgr_test.go
--- snapd-2.0.5/asserts/memkeypairmgr_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/memkeypairmgr_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
type memKeypairMgtSuite struct {
@@ -36,7 +36,7 @@
}
func (mkms *memKeypairMgtSuite) TestPutAndGet(c *C) {
- pk1 := asserts.OpenPGPPrivateKey(testPrivKey1)
+ pk1 := testPrivKey1
keyID := pk1.PublicKey().ID()
err := mkms.keypairMgr.Put("auth-id1", pk1)
c.Assert(err, IsNil)
@@ -48,7 +48,7 @@
}
func (mkms *memKeypairMgtSuite) TestPutAlreadyExists(c *C) {
- pk1 := asserts.OpenPGPPrivateKey(testPrivKey1)
+ pk1 := testPrivKey1
err := mkms.keypairMgr.Put("auth-id1", pk1)
c.Assert(err, IsNil)
@@ -57,17 +57,17 @@
}
func (mkms *memKeypairMgtSuite) TestGetNotFound(c *C) {
- pk1 := asserts.OpenPGPPrivateKey(testPrivKey1)
+ pk1 := testPrivKey1
keyID := pk1.PublicKey().ID()
got, err := mkms.keypairMgr.Get("auth-id1", keyID)
c.Check(got, IsNil)
- c.Check(err, ErrorMatches, "no matching key pair found")
+ c.Check(err, ErrorMatches, "cannot find key pair")
err = mkms.keypairMgr.Put("auth-id1", pk1)
c.Assert(err, IsNil)
got, err = mkms.keypairMgr.Get("auth-id1", keyID+"x")
c.Check(got, IsNil)
- c.Check(err, ErrorMatches, "no matching key pair found")
+ c.Check(err, ErrorMatches, "cannot find key pair")
}
diff -Nru snapd-2.0.5/asserts/privkeys_for_test.go snapd-2.0.8/asserts/privkeys_for_test.go
--- snapd-2.0.5/asserts/privkeys_for_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/privkeys_for_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,7 @@
import (
"fmt"
- "golang.org/x/crypto/openpgp/packet"
-
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
// private keys to use in tests
@@ -32,10 +30,12 @@
testPrivKey0 = genTestPrivKey()
testPrivKey1 = genTestPrivKey()
testPrivKey2 = genTestPrivKey()
+
+ testPrivKey1Pkt = asserts.PrivateKeyPacket(testPrivKey1)
)
-func genTestPrivKey() *packet.PrivateKey {
- privKey, err := asserts.GeneratePrivateKeyInTest()
+func genTestPrivKey() asserts.PrivateKey {
+ privKey, err := asserts.GenerateKey()
if err != nil {
panic(fmt.Errorf("failed to create priv key for tests: %v", err))
}
diff -Nru snapd-2.0.5/asserts/snap_asserts.go snapd-2.0.8/asserts/snap_asserts.go
--- snapd-2.0.5/asserts/snap_asserts.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/snap_asserts.go 2016-06-08 05:58:01.000000000 +0000
@@ -65,12 +65,12 @@
// XXX: consistency check is signed by canonical
func assembleSnapDeclaration(assert assertionBase) (Assertion, error) {
- _, err := checkMandatory(assert.headers, "snap-name")
+ _, err := checkExists(assert.headers, "snap-name")
if err != nil {
return nil, err
}
- _, err = checkMandatory(assert.headers, "publisher-id")
+ _, err = checkNotEmpty(assert.headers, "publisher-id")
if err != nil {
return nil, err
}
@@ -134,7 +134,7 @@
func assembleSnapBuild(assert assertionBase) (Assertion, error) {
// TODO: more parsing/checking of snap-digest
- _, err := checkMandatory(assert.headers, "grade")
+ _, err := checkNotEmpty(assert.headers, "grade")
if err != nil {
return nil, err
}
@@ -225,7 +225,7 @@
return nil, err
}
- _, err = checkMandatory(assert.headers, "developer-id")
+ _, err = checkNotEmpty(assert.headers, "developer-id")
if err != nil {
return nil, err
}
diff -Nru snapd-2.0.5/asserts/snap_asserts_test.go snapd-2.0.8/asserts/snap_asserts_test.go
--- snapd-2.0.5/asserts/snap_asserts_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/snap_asserts_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
var (
@@ -70,6 +70,24 @@
c.Check(snapDecl.Gates(), DeepEquals, []string{"snap-id-3", "snap-id-4"})
}
+func (sds *snapDeclSuite) TestEmptySnapName(c *C) {
+ encoded := "type: snap-declaration\n" +
+ "authority-id: canonical\n" +
+ "series: 16\n" +
+ "snap-id: snap-id-1\n" +
+ "snap-name: \n" +
+ "publisher-id: dev-id1\n" +
+ "gates: snap-id-3,snap-id-4\n" +
+ sds.tsLine +
+ "body-length: 0" +
+ "\n\n" +
+ "openpgp c2ln"
+ a, err := asserts.Decode([]byte(encoded))
+ c.Assert(err, IsNil)
+ snapDecl := a.(*asserts.SnapDeclaration)
+ c.Check(snapDecl.SnapName(), Equals, "")
+}
+
const (
snapDeclErrPrefix = "assertion snap-declaration: "
)
@@ -89,12 +107,17 @@
invalidTests := []struct{ original, invalid, expectedErr string }{
{"series: 16\n", "", `"series" header is mandatory`},
+ {"series: 16\n", "series: \n", `"series" header should not be empty`},
{"snap-id: snap-id-1\n", "", `"snap-id" header is mandatory`},
+ {"snap-id: snap-id-1\n", "snap-id: \n", `"snap-id" header should not be empty`},
{"snap-name: first\n", "", `"snap-name" header is mandatory`},
{"publisher-id: dev-id1\n", "", `"publisher-id" header is mandatory`},
+ {"publisher-id: dev-id1\n", "publisher-id: \n", `"publisher-id" header should not be empty`},
+ {sds.tsLine, "", `"timestamp" header is mandatory`},
+ {sds.tsLine, "timestamp: \n", `"timestamp" header should not be empty`},
+ {sds.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
{"gates: snap-id-3,snap-id-4\n", "", `\"gates\" header is mandatory`},
{"gates: snap-id-3,snap-id-4\n", "gates: foo,\n", `empty entry in comma separated "gates" header: "foo,"`},
- {sds.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
}
for _, test := range invalidTests {
@@ -159,12 +182,18 @@
invalidTests := []struct{ original, invalid, expectedErr string }{
{"series: 16\n", "", `"series" header is mandatory`},
+ {"series: 16\n", "series: \n", `"series" header should not be empty`},
{"snap-id: snap-id-1\n", "", `"snap-id" header is mandatory`},
+ {"snap-id: snap-id-1\n", "snap-id: \n", `"snap-id" header should not be empty`},
{"snap-digest: sha256 ...\n", "", `"snap-digest" header is mandatory`},
- {"grade: stable\n", "", `"grade" header is mandatory`},
+ {"snap-digest: sha256 ...\n", "snap-digest: \n", `"snap-digest" header should not be empty`},
{"snap-size: 10000\n", "", `"snap-size" header is mandatory`},
{"snap-size: 10000\n", "snap-size: -1\n", `"snap-size" header is not an unsigned integer: -1`},
{"snap-size: 10000\n", "snap-size: zzz\n", `"snap-size" header is not an unsigned integer: zzz`},
+ {"grade: stable\n", "", `"grade" header is mandatory`},
+ {"grade: stable\n", "grade: \n", `"grade" header should not be empty`},
+ {sbs.tsLine, "", `"timestamp" header is mandatory`},
+ {sbs.tsLine, "timestamp: \n", `"timestamp" header should not be empty`},
{sbs.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
}
@@ -183,8 +212,8 @@
}
accSignDB, err := asserts.OpenDatabase(cfg1)
c.Assert(err, IsNil)
- pk1 := asserts.OpenPGPPrivateKey(testPrivKey1)
- err = accSignDB.ImportKey(accountID, asserts.OpenPGPPrivateKey(testPrivKey1))
+ pk1 := testPrivKey1
+ err = accSignDB.ImportKey(accountID, testPrivKey1)
c.Assert(err, IsNil)
accFingerp := pk1.PublicKey().Fingerprint()
accKeyID := pk1.PublicKey().ID()
@@ -203,7 +232,7 @@
"since": "2015-11-20T15:04:00Z",
"until": "2500-11-20T15:04:00Z",
}
- accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(accPubKeyBody), asserts.OpenPGPPrivateKey(trustedKey))
+ accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(accPubKeyBody), trustedKey)
c.Assert(err, IsNil)
topDir := filepath.Join(c.MkDir(), "asserts-db")
@@ -212,7 +241,7 @@
cfg := &asserts.DatabaseConfig{
Backstore: bs,
KeypairManager: asserts.NewMemoryKeypairManager(),
- TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", &trustedKey.PublicKey)},
+ TrustedKeys: []*asserts.AccountKey{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
}
checkDB, err = asserts.OpenDatabase(cfg)
c.Assert(err, IsNil)
@@ -331,15 +360,23 @@
encoded := srs.makeValidEncoded()
invalidTests := []struct{ original, invalid, expectedErr string }{
{"series: 16\n", "", `"series" header is mandatory`},
+ {"series: 16\n", "series: \n", `"series" header should not be empty`},
{"snap-id: snap-id-1\n", "", `"snap-id" header is mandatory`},
+ {"snap-id: snap-id-1\n", "snap-id: \n", `"snap-id" header should not be empty`},
{"snap-digest: sha256 ...\n", "", `"snap-digest" header is mandatory`},
+ {"snap-digest: sha256 ...\n", "snap-digest: \n", `"snap-digest" header should not be empty`},
{"snap-size: 123\n", "", `"snap-size" header is mandatory`},
+ {"snap-size: 123\n", "snap-size: \n", `"snap-size" header should not be empty`},
{"snap-size: 123\n", "snap-size: -1\n", `"snap-size" header is not an unsigned integer: -1`},
{"snap-size: 123\n", "snap-size: zzz\n", `"snap-size" header is not an unsigned integer: zzz`},
{"snap-revision: 1\n", "", `"snap-revision" header is mandatory`},
+ {"snap-revision: 1\n", "snap-revision: \n", `"snap-revision" header should not be empty`},
{"snap-revision: 1\n", "snap-revision: -1\n", `"snap-revision" header is not an unsigned integer: -1`},
{"snap-revision: 1\n", "snap-revision: zzz\n", `"snap-revision" header is not an unsigned integer: zzz`},
{"developer-id: dev-id1\n", "", `"developer-id" header is mandatory`},
+ {"developer-id: dev-id1\n", "developer-id: \n", `"developer-id" header should not be empty`},
+ {srs.tsLine, "", `"timestamp" header is mandatory`},
+ {srs.tsLine, "timestamp: \n", `"timestamp" header should not be empty`},
{srs.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`},
}
diff -Nru snapd-2.0.5/asserts/sysdb.go snapd-2.0.8/asserts/sysdb.go
--- snapd-2.0.5/asserts/sysdb.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/sysdb.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,7 +23,7 @@
"fmt"
"io/ioutil"
- "github.com/ubuntu-core/snappy/dirs"
+ "github.com/snapcore/snapd/dirs"
)
func openDatabaseAt(path string, cfg *DatabaseConfig) (*Database, error) {
diff -Nru snapd-2.0.5/asserts/sysdb_test.go snapd-2.0.8/asserts/sysdb_test.go
--- snapd-2.0.5/asserts/sysdb_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/asserts/sysdb_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,8 +27,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/dirs"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/dirs"
)
type sysDBSuite struct {
@@ -40,7 +40,7 @@
func (sdbs *sysDBSuite) SetUpTest(c *C) {
tmpdir := c.MkDir()
- pk := asserts.OpenPGPPrivateKey(testPrivKey0)
+ pk := testPrivKey0
trustedPubKey := pk.PublicKey()
trustedPubKeyEncoded, err := asserts.EncodePublicKey(trustedPubKey)
c.Assert(err, IsNil)
diff -Nru snapd-2.0.5/classic/create.go snapd-2.0.8/classic/create.go
--- snapd-2.0.5/classic/create.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/classic/create.go 2016-06-08 05:58:01.000000000 +0000
@@ -30,11 +30,11 @@
"path/filepath"
"strings"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/release"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/release"
)
var (
@@ -47,13 +47,9 @@
func findDownloadPathFromLxdIndex(r io.Reader) (string, error) {
arch := arch.UbuntuArchitecture()
- lsb, err := release.ReadLSB()
- if err != nil {
- return "", err
- }
- release := lsb.Codename
+ codename := release.ReleaseInfo.Codename
- needle := fmt.Sprintf("ubuntu;%s;%s;default;", release, arch)
+ needle := fmt.Sprintf("ubuntu;%s;%s;default;", codename, arch)
scanner := bufio.NewScanner(r)
for scanner.Scan() {
if strings.HasPrefix(scanner.Text(), needle) {
diff -Nru snapd-2.0.5/classic/create_test.go snapd-2.0.8/classic/create_test.go
--- snapd-2.0.5/classic/create_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/classic/create_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -32,12 +32,12 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/release"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/testutil"
)
type CreateTestSuite struct {
@@ -52,6 +52,9 @@
func (t *CreateTestSuite) SetUpTest(c *C) {
t.BaseTest.SetUpTest(c)
+ if release.ReleaseInfo.ID != "ubuntu" {
+ c.Skip("classic test only work on ubuntu")
+ }
dirs.SetRootDir(c.MkDir())
@@ -78,16 +81,12 @@
}
func makeMockLxdIndexSystem() string {
- lsb, err := release.ReadLSB()
- if err != nil {
- panic(err)
- }
arch := arch.UbuntuArchitecture()
s := fmt.Sprintf(`
ubuntu;xenial;otherarch;default;20151126_03:49;/images/ubuntu/xenial/armhf/default/20151126_03:49/
ubuntu;%s;%s;default;20151126_03:49;/images/ubuntu/CODENAME/ARCH/default/20151126_03:49/
-`, lsb.Codename, arch)
+`, release.ReleaseInfo.Codename, arch)
return s
}
diff -Nru snapd-2.0.5/classic/enabled_test.go snapd-2.0.8/classic/enabled_test.go
--- snapd-2.0.5/classic/enabled_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/classic/enabled_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/testutil"
)
type EnabledTestSuite struct {
diff -Nru snapd-2.0.5/classic/helpers.go snapd-2.0.8/classic/helpers.go
--- snapd-2.0.5/classic/helpers.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/classic/helpers.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
"path/filepath"
"strings"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
)
// Enabled returns true if the classic mode is already enabled
diff -Nru snapd-2.0.5/classic/helpers_test.go snapd-2.0.8/classic/helpers_test.go
--- snapd-2.0.5/classic/helpers_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/classic/helpers_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,7 +25,7 @@
"io/ioutil"
"path/filepath"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/testutil"
)
type HelpersTestSuite struct {
diff -Nru snapd-2.0.5/classic/run.go snapd-2.0.8/classic/run.go
--- snapd-2.0.5/classic/run.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/classic/run.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
"path/filepath"
"time"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/strutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/strutil"
)
type bindMount struct {
diff -Nru snapd-2.0.5/client/asserts.go snapd-2.0.8/client/asserts.go
--- snapd-2.0.5/client/asserts.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/asserts.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
"net/url"
"strconv"
- "github.com/ubuntu-core/snappy/asserts" // for parsing
+ "github.com/snapcore/snapd/asserts" // for parsing
)
// Ack tries to add an assertion to the system assertion
diff -Nru snapd-2.0.5/client/asserts_test.go snapd-2.0.8/client/asserts_test.go
--- snapd-2.0.5/client/asserts_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/asserts_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
+ "github.com/snapcore/snapd/asserts"
)
func (cs *clientSuite) TestClientAssert(c *C) {
diff -Nru snapd-2.0.5/client/change.go snapd-2.0.8/client/change.go
--- snapd-2.0.5/client/change.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/change.go 2016-06-08 05:58:01.000000000 +0000
@@ -130,9 +130,21 @@
ChangesAll = ChangesReady | ChangesInProgress
)
-func (client *Client) Changes(which ChangeSelector) ([]*Change, error) {
+type ChangesOptions struct {
+ SnapName string // if empty, no filtering by name is done
+ Selector ChangeSelector
+}
+
+func (client *Client) Changes(opts *ChangesOptions) ([]*Change, error) {
query := url.Values{}
- query.Set("select", which.String())
+ if opts != nil {
+ if opts.Selector != 0 {
+ query.Set("select", opts.Selector.String())
+ }
+ if opts.SnapName != "" {
+ query.Set("for", opts.SnapName)
+ }
+ }
var chgds []changeAndData
_, err := client.doSync("GET", "/v2/changes", query, nil, nil, &chgds)
diff -Nru snapd-2.0.5/client/change_test.go snapd-2.0.8/client/change_test.go
--- snapd-2.0.5/client/change_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/change_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/client"
+ "github.com/snapcore/snapd/client"
"io/ioutil"
"time"
)
@@ -131,7 +131,13 @@
"tasks": [{"kind": "bar", "summary": "...", "status": "Do", "progress": {"done": 0, "total": 1}}]
}]}`
- for _, i := range []client.ChangeSelector{client.ChangesAll, client.ChangesReady, client.ChangesInProgress} {
+ for _, i := range []*client.ChangesOptions{
+ {Selector: client.ChangesAll},
+ {Selector: client.ChangesReady},
+ {Selector: client.ChangesInProgress},
+ {SnapName: "foo"},
+ nil,
+ } {
chg, err := cs.cli.Changes(i)
c.Assert(err, check.IsNil)
c.Check(chg, check.DeepEquals, []*client.Change{{
@@ -141,8 +147,17 @@
Status: "Do",
Tasks: []*client.Task{{Kind: "bar", Summary: "...", Status: "Do", Progress: client.TaskProgress{Done: 0, Total: 1}}},
}})
- c.Check(cs.req.URL.RawQuery, check.Equals, "select="+i.String())
+ if i == nil {
+ c.Check(cs.req.URL.RawQuery, check.Equals, "")
+ } else {
+ if i.Selector != 0 {
+ c.Check(cs.req.URL.RawQuery, check.Equals, "select="+i.Selector.String())
+ } else {
+ c.Check(cs.req.URL.RawQuery, check.Equals, "for="+i.SnapName)
+ }
+ }
}
+
}
func (cs *clientSuite) TestClientChangesData(c *check.C) {
@@ -155,7 +170,7 @@
"data": {"n": 42}
}]}`
- chgs, err := cs.cli.Changes(client.ChangesAll)
+ chgs, err := cs.cli.Changes(&client.ChangesOptions{Selector: client.ChangesAll})
c.Assert(err, check.IsNil)
chg := chgs[0]
diff -Nru snapd-2.0.5/client/client.go snapd-2.0.8/client/client.go
--- snapd-2.0.5/client/client.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/client.go 2016-06-08 05:58:01.000000000 +0000
@@ -30,7 +30,7 @@
"os"
"path"
- "github.com/ubuntu-core/snappy/dirs"
+ "github.com/snapcore/snapd/dirs"
)
func unixDialer(_, _ string) (net.Conn, error) {
@@ -189,6 +189,20 @@
return rsp.Change, nil
}
+func (client *Client) ServerVersion() (string, error) {
+ sysInfo, err := client.SysInfo()
+ if err != nil {
+ return "unknown", err
+ }
+
+ version := sysInfo.Version
+ if version == "" {
+ version = "unknown"
+ }
+
+ return fmt.Sprintf("%s (series %s)", version, sysInfo.Series), nil
+}
+
// A response produced by the REST API will usually fit in this
// (exceptions are the icons/ endpoints obvs)
type response struct {
@@ -232,11 +246,8 @@
// SysInfo holds system information
type SysInfo struct {
- Flavor string `json:"flavor"`
- Release string `json:"release"`
- DefaultChannel string `json:"default-channel"`
- APICompatibility string `json:"api-compat"`
- Store string `json:"store,omitempty"`
+ Series string `json:"series,omitempty"`
+ Version string `json:"version,omitempty"`
}
func (rsp *response) err() error {
diff -Nru snapd-2.0.5/client/client_test.go snapd-2.0.8/client/client_test.go
--- snapd-2.0.5/client/client_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/client_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -33,8 +33,8 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/client"
- "github.com/ubuntu-core/snappy/dirs"
+ "github.com/snapcore/snapd/client"
+ "github.com/snapcore/snapd/dirs"
)
// Hook up check.v1 into the "go test" runner
@@ -78,23 +78,6 @@
client.New(&client.Config{BaseURL: ":"})
}, check.PanicMatches, `cannot parse server base URL: ":" \(parse :: missing protocol scheme\)`)
}
-
-func (cs *clientSuite) TestNewCustomURL(c *check.C) {
- f := func(w http.ResponseWriter, r *http.Request) {
- c.Check(r.URL.Path, check.Equals, "/v2/system-info")
- c.Check(r.URL.RawQuery, check.Equals, "")
- fmt.Fprintln(w, `{"type":"sync", "result":{"store":"X"}}`)
- }
- srv := httptest.NewServer(http.HandlerFunc(f))
- defer srv.Close()
-
- cli := client.New(&client.Config{BaseURL: srv.URL})
- c.Assert(cli, check.Not(check.IsNil))
- si, err := cli.SysInfo()
- c.Check(err, check.IsNil)
- c.Check(si.Store, check.Equals, "X")
-}
-
func (cs *clientSuite) TestClientDoReportsErrors(c *check.C) {
cs.err = errors.New("ouchie")
err := cs.cli.Do("GET", "/", nil, nil, nil)
@@ -148,19 +131,13 @@
func (cs *clientSuite) TestClientSysInfo(c *check.C) {
cs.rsp = `{"type": "sync", "result":
- {"flavor": "f",
- "release": "r",
- "default-channel": "dc",
- "api-compat": "42",
- "store": "store"}}`
+ {"series": "16",
+ "version": "2"}}`
sysInfo, err := cs.cli.SysInfo()
c.Check(err, check.IsNil)
c.Check(sysInfo, check.DeepEquals, &client.SysInfo{
- Flavor: "f",
- Release: "r",
- DefaultChannel: "dc",
- APICompatibility: "42",
- Store: "store",
+ Version: "2",
+ Series: "16",
})
}
@@ -175,7 +152,7 @@
c.Check(r.URL.Path, check.Equals, "/v2/system-info")
c.Check(r.URL.RawQuery, check.Equals, "")
- fmt.Fprintln(w, `{"type":"sync", "result":{"store":"X"}}`)
+ fmt.Fprintln(w, `{"type":"sync", "result":{"series":"42"}}`)
}
srv := &httptest.Server{
@@ -188,7 +165,7 @@
cli := client.New(nil)
si, err := cli.SysInfo()
c.Check(err, check.IsNil)
- c.Check(si.Store, check.Equals, "X")
+ c.Check(si.Series, check.Equals, "42")
}
func (cs *clientSuite) TestClientReportsOpError(c *check.C) {
diff -Nru snapd-2.0.5/client/interfaces_test.go snapd-2.0.8/client/interfaces_test.go
--- snapd-2.0.5/client/interfaces_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/interfaces_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/client"
+ "github.com/snapcore/snapd/client"
)
func (cs *clientSuite) TestClientInterfacesCallsEndpoint(c *check.C) {
diff -Nru snapd-2.0.5/client/login.go snapd-2.0.8/client/login.go
--- snapd-2.0.5/client/login.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/login.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
// User holds logged in user information.
diff -Nru snapd-2.0.5/client/login_test.go snapd-2.0.8/client/login_test.go
--- snapd-2.0.5/client/login_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/login_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,8 +27,8 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/client"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/client"
+ "github.com/snapcore/snapd/osutil"
)
func (cs *clientSuite) TestClientLogin(c *check.C) {
diff -Nru snapd-2.0.5/client/packages.go snapd-2.0.8/client/packages.go
--- snapd-2.0.5/client/packages.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/packages.go 2016-06-08 05:58:01.000000000 +0000
@@ -39,7 +39,12 @@
Status string `json:"status"`
Type string `json:"type"`
Version string `json:"version"`
- Revision int `json:"revision"`
+ Channel string `json:"channel"`
+ Revision Revision `json:"revision"`
+ Confinement string `json:"confinement"`
+ Private bool `json:"private"`
+ DevMode bool `json:"devmode"`
+ TryMode bool `json:"trymode"`
Prices map[string]float64 `json:"prices"`
}
@@ -55,15 +60,26 @@
TypeKernel = "kernel"
TypeGadget = "gadget"
TypeOS = "os"
+
+ StrictConfinement = "strict"
+ DevmodeConfinement = "devmode"
)
type ResultInfo struct {
SuggestedCurrency string `json:"suggested-currency"`
}
-// ListSnaps returns the list of all snaps installed on the system
+// FindOptions supports exactly one of the following options:
+// - Refresh: only return snaps that are refreshable
+// - Query: only return snaps that match the query string
+type FindOptions struct {
+ Refresh bool
+ Query string
+}
+
+// List returns the list of all snaps installed on the system
// with names in the given list; if the list is empty, all snaps.
-func (client *Client) ListSnaps(names []string) ([]*Snap, error) {
+func (client *Client) List(names []string) ([]*Snap, error) {
snaps, _, err := client.snapsFromPath("/v2/snaps", nil)
if err != nil {
return nil, err
@@ -88,12 +104,18 @@
return result, nil
}
-// FindSnaps returns a list of snaps available for install from the
+// Find returns a list of snaps available for install from the
// store for this system and that match the query
-func (client *Client) FindSnaps(query string) ([]*Snap, *ResultInfo, error) {
- q := url.Values{}
+func (client *Client) Find(opts *FindOptions) ([]*Snap, *ResultInfo, error) {
+ if opts == nil {
+ opts = &FindOptions{}
+ }
- q.Set("q", query)
+ q := url.Values{}
+ q.Set("q", opts.Query)
+ if opts.Refresh {
+ q.Set("select", "refresh")
+ }
return client.snapsFromPath("/v2/find", q)
}
diff -Nru snapd-2.0.5/client/packages_test.go snapd-2.0.8/client/packages_test.go
--- snapd-2.0.5/client/packages_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/packages_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -21,17 +21,30 @@
import (
"fmt"
+ "net/url"
"time"
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/client"
+ "github.com/snapcore/snapd/client"
)
func (cs *clientSuite) TestClientSnapsCallsEndpoint(c *check.C) {
- _, _ = cs.cli.ListSnaps(nil)
+ _, _ = cs.cli.List(nil)
c.Check(cs.req.Method, check.Equals, "GET")
c.Check(cs.req.URL.Path, check.Equals, "/v2/snaps")
+ c.Check(cs.req.URL.Query(), check.DeepEquals, url.Values{})
+}
+
+func (cs *clientSuite) TestClientFindRefreshSetsQuery(c *check.C) {
+ _, _, _ = cs.cli.Find(&client.FindOptions{
+ Refresh: true,
+ })
+ c.Check(cs.req.Method, check.Equals, "GET")
+ c.Check(cs.req.URL.Path, check.Equals, "/v2/find")
+ c.Check(cs.req.URL.Query(), check.DeepEquals, url.Values{
+ "q": []string{""}, "select": []string{"refresh"},
+ })
}
func (cs *clientSuite) TestClientSnapsInvalidSnapsJSON(c *check.C) {
@@ -39,7 +52,7 @@
"type": "sync",
"result": "not a list of snaps"
}`
- _, err := cs.cli.ListSnaps(nil)
+ _, err := cs.cli.List(nil)
c.Check(err, check.ErrorMatches, `.*cannot unmarshal.*`)
}
@@ -58,11 +71,13 @@
"resource": "/v2/snaps/hello-world.canonical",
"status": "available",
"type": "app",
- "version": "1.0.18"
+ "version": "1.0.18",
+ "confinement": "strict",
+ "private": true
}],
"suggested-currency": "GBP"
}`
- applications, err := cs.cli.ListSnaps(nil)
+ applications, err := cs.cli.List(nil)
c.Check(err, check.IsNil)
c.Check(applications, check.DeepEquals, []*client.Snap{{
ID: "funky-snap-id",
@@ -76,14 +91,17 @@
Status: client.StatusAvailable,
Type: client.TypeApp,
Version: "1.0.18",
+ Confinement: client.StrictConfinement,
+ Private: true,
+ DevMode: false,
}})
- otherApps, err := cs.cli.ListSnaps([]string{"foo"})
+ otherApps, err := cs.cli.List([]string{"foo"})
c.Check(err, check.IsNil)
c.Check(otherApps, check.HasLen, 0)
}
func (cs *clientSuite) TestClientFilterSnaps(c *check.C) {
- _, _, _ = cs.cli.FindSnaps("foo")
+ _, _, _ = cs.cli.Find(&client.FindOptions{Query: "foo"})
c.Check(cs.req.URL.Path, check.Equals, "/v2/find")
c.Check(cs.req.URL.RawQuery, check.Equals, "q=foo")
}
@@ -108,7 +126,11 @@
"resource": "/v2/snaps/chatroom.ogra",
"status": "active",
"type": "app",
- "version": "0.1-8"
+ "version": "0.1-8",
+ "confinement": "strict",
+ "private": true,
+ "devmode": true,
+ "trymode": true
}
}`
pkg, _, err := cs.cli.Snap(pkgName)
@@ -128,5 +150,9 @@
Status: client.StatusActive,
Type: client.TypeApp,
Version: "0.1-8",
+ Confinement: client.StrictConfinement,
+ Private: true,
+ DevMode: true,
+ TryMode: true,
})
}
diff -Nru snapd-2.0.5/client/revision.go snapd-2.0.8/client/revision.go
--- snapd-2.0.5/client/revision.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/client/revision.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,111 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package client
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Keep this in sync between snap and client packages.
+
+type Revision struct {
+ N int
+}
+
+func (r Revision) String() string {
+ if r.N == 0 {
+ return "unset"
+ }
+ if r.N < 0 {
+ return fmt.Sprintf("x%d", -r.N)
+ }
+ return strconv.Itoa(int(r.N))
+}
+
+func (r Revision) Unset() bool {
+ return r.N == 0
+}
+
+func (r Revision) Local() bool {
+ return r.N < 0
+}
+
+func (r Revision) Store() bool {
+ return r.N > 0
+}
+
+func (r Revision) MarshalJSON() ([]byte, error) {
+ return []byte(`"` + r.String() + `"`), nil
+}
+
+func (r *Revision) UnmarshalJSON(data []byte) error {
+ if len(data) > 0 && data[0] == '"' && data[len(data)-1] == '"' {
+ parsed, err := ParseRevision(string(data[1 : len(data)-1]))
+ if err == nil {
+ *r = parsed
+ return nil
+ }
+ } else {
+ n, err := strconv.ParseInt(string(data), 10, 64)
+ if err == nil {
+ r.N = int(n)
+ return nil
+ }
+ }
+ return fmt.Errorf("invalid snap revision: %q", data)
+}
+
+// ParseRevisions returns the representation in r as a revision.
+// See R for a function more suitable for hardcoded revisions.
+func ParseRevision(s string) (Revision, error) {
+ if s == "unset" {
+ return Revision{}, nil
+ }
+ if s != "" && s[0] == 'x' {
+ i, err := strconv.Atoi(s[1:])
+ if err == nil && i > 0 {
+ return Revision{-i}, nil
+ }
+ }
+ i, err := strconv.Atoi(s)
+ if err == nil && i > 0 {
+ return Revision{i}, nil
+ }
+ return Revision{}, fmt.Errorf("invalid snap revision: %#v", s)
+}
+
+// R returns a Revision given an int or a string.
+// Providing an invalid revision type or value causes a runtime panic.
+// See ParseRevision for a polite function that does not panic.
+func R(r interface{}) Revision {
+ switch r := r.(type) {
+ case string:
+ revision, err := ParseRevision(r)
+ if err != nil {
+ panic(err)
+ }
+ return revision
+ case int:
+ return Revision{r}
+ default:
+ panic(fmt.Errorf("cannot use %v (%T) as a snap revision", r, r))
+ }
+}
diff -Nru snapd-2.0.5/client/revision_test.go snapd-2.0.8/client/revision_test.go
--- snapd-2.0.5/client/revision_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/client/revision_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,171 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package client_test
+
+import (
+ "encoding/json"
+ "strconv"
+
+ . "gopkg.in/check.v1"
+
+ . "github.com/snapcore/snapd/snap"
+)
+
+// Keep this in sync between snap and client packages.
+
+type revisionSuite struct{}
+
+var _ = Suite(&revisionSuite{})
+
+func (s revisionSuite) TestString(c *C) {
+ c.Assert(Revision{0}.String(), Equals, "unset")
+ c.Assert(Revision{10}.String(), Equals, "10")
+ c.Assert(Revision{-9}.String(), Equals, "x9")
+}
+
+func (s revisionSuite) TestUnset(c *C) {
+ c.Assert(Revision{0}.Unset(), Equals, true)
+ c.Assert(Revision{10}.Unset(), Equals, false)
+ c.Assert(Revision{-9}.Unset(), Equals, false)
+}
+
+func (s revisionSuite) TestLocal(c *C) {
+ c.Assert(Revision{0}.Local(), Equals, false)
+ c.Assert(Revision{10}.Local(), Equals, false)
+ c.Assert(Revision{-9}.Local(), Equals, true)
+}
+
+func (s revisionSuite) TestStore(c *C) {
+ c.Assert(Revision{0}.Store(), Equals, false)
+ c.Assert(Revision{10}.Store(), Equals, true)
+ c.Assert(Revision{-9}.Store(), Equals, false)
+}
+
+func (s revisionSuite) TestJSON(c *C) {
+ for _, n := range []int{0, 10, -9} {
+ r := Revision{n}
+ data, err := json.Marshal(Revision{n})
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, `"`+r.String()+`"`)
+
+ var got Revision
+ err = json.Unmarshal(data, &got)
+ c.Assert(err, IsNil)
+ c.Assert(got, Equals, r)
+
+ got = Revision{}
+ err = json.Unmarshal([]byte(strconv.Itoa(r.N)), &got)
+ c.Assert(err, IsNil)
+ c.Assert(got, Equals, r)
+ }
+}
+
+func (s revisionSuite) ParseRevision(c *C) {
+ type testItem struct {
+ s string
+ n int
+ e string
+ }
+
+ var tests = []testItem{{
+ s: "unset",
+ n: 0,
+ }, {
+ s: "x1",
+ n: -1,
+ }, {
+ s: "1",
+ n: 1,
+ }, {
+ s: "x-1",
+ e: `invalid snap revision: "x-1"`,
+ }, {
+ s: "x0",
+ e: `invalid snap revision: "x0"`,
+ }, {
+ s: "-1",
+ e: `invalid snap revision: "-1"`,
+ }, {
+ s: "0",
+ e: `invalid snap revision: "0"`,
+ }}
+
+ for _, test := range tests {
+ r, err := ParseRevision(test.s)
+ if test.e != "" {
+ c.Assert(err.Error(), Equals, test.e)
+ continue
+ }
+ c.Assert(r, Equals, Revision{test.n})
+ }
+}
+
+func (s *revisionSuite) TestR(c *C) {
+ type testItem struct {
+ v interface{}
+ n int
+ e string
+ }
+
+ var tests = []testItem{{
+ v: 0,
+ n: 0,
+ }, {
+ v: -1,
+ n: -1,
+ }, {
+ v: 1,
+ n: 1,
+ }, {
+ v: "unset",
+ n: 0,
+ }, {
+ v: "x1",
+ n: -1,
+ }, {
+ v: "1",
+ n: 1,
+ }, {
+ v: "x-1",
+ e: `invalid snap revision: "x-1"`,
+ }, {
+ v: "x0",
+ e: `invalid snap revision: "x0"`,
+ }, {
+ v: "-1",
+ e: `invalid snap revision: "-1"`,
+ }, {
+ v: "0",
+ e: `invalid snap revision: "0"`,
+ }, {
+ v: int64(1),
+ e: `cannot use 1 \(int64\) as a snap revision`,
+ }}
+
+ for _, test := range tests {
+ if test.e != "" {
+ f := func() { R(test.v) }
+ c.Assert(f, PanicMatches, test.e)
+ continue
+ }
+
+ c.Assert(R(test.v), Equals, Revision{test.n})
+ }
+}
diff -Nru snapd-2.0.5/client/snap_op.go snapd-2.0.8/client/snap_op.go
--- snapd-2.0.5/client/snap_op.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/snap_op.go 2016-06-08 05:58:01.000000000 +0000
@@ -98,6 +98,26 @@
return client.doAsync("POST", "/v2/snaps", nil, headers, pr)
}
+// Try
+func (client *Client) Try(path string, options *SnapOptions) (changeID string, err error) {
+ if options == nil {
+ options = &SnapOptions{}
+ }
+
+ buf := bytes.NewBuffer(nil)
+ mw := multipart.NewWriter(buf)
+ mw.WriteField("action", "try")
+ mw.WriteField("snap-path", path)
+ mw.WriteField("devmode", strconv.FormatBool(options.DevMode))
+ mw.Close()
+
+ headers := map[string]string{
+ "Content-Type": mw.FormDataContentType(),
+ }
+
+ return client.doAsync("POST", "/v2/snaps", nil, headers, buf)
+}
+
func sendSnapFile(snapPath string, snapFile *os.File, pw *io.PipeWriter, mw *multipart.Writer, action *actionData) {
defer snapFile.Close()
diff -Nru snapd-2.0.5/client/snap_op_test.go snapd-2.0.8/client/snap_op_test.go
--- snapd-2.0.5/client/snap_op_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/client/snap_op_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,12 +23,16 @@
"encoding/json"
"errors"
"fmt"
+ "io"
"io/ioutil"
+ "mime"
+ "mime/multipart"
"path/filepath"
+ "strconv"
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/client"
+ "github.com/snapcore/snapd/client"
)
var chanName = "achan"
@@ -140,3 +144,51 @@
c.Assert(cs.req.Header.Get("Content-Type"), check.Matches, "multipart/form-data; boundary=.*")
c.Check(id, check.Equals, "66b3")
}
+
+func formToMap(c *check.C, mr *multipart.Reader) map[string]string {
+ formData := map[string]string{}
+ for {
+ p, err := mr.NextPart()
+ if err == io.EOF {
+ break
+ }
+ c.Assert(err, check.IsNil)
+ slurp, err := ioutil.ReadAll(p)
+ c.Assert(err, check.IsNil)
+ formData[p.FormName()] = string(slurp)
+ }
+ return formData
+}
+
+func (cs *clientSuite) TestClientOpTryMode(c *check.C) {
+ cs.rsp = `{
+ "change": "66b3",
+ "status-code": 202,
+ "type": "async"
+ }`
+ snapdir := filepath.Join(c.MkDir(), "/some/path")
+
+ for _, opts := range []*client.SnapOptions{
+ {DevMode: false},
+ {DevMode: true},
+ } {
+ id, err := cs.cli.Try(snapdir, opts)
+ c.Assert(err, check.IsNil)
+
+ // ensure we send the right form-data
+ _, params, err := mime.ParseMediaType(cs.req.Header.Get("Content-Type"))
+ c.Assert(err, check.IsNil)
+ mr := multipart.NewReader(cs.req.Body, params["boundary"])
+ formData := formToMap(c, mr)
+ c.Check(formData, check.DeepEquals, map[string]string{
+ "action": "try",
+ "snap-path": snapdir,
+ "devmode": strconv.FormatBool(opts.DevMode),
+ })
+
+ c.Check(cs.req.Method, check.Equals, "POST")
+ c.Check(cs.req.URL.Path, check.Equals, fmt.Sprintf("/v2/snaps"))
+ c.Assert(cs.req.Header.Get("Content-Type"), check.Matches, "multipart/form-data; boundary=.*")
+ c.Check(id, check.Equals, "66b3")
+ }
+}
diff -Nru snapd-2.0.5/cmd/cmd.go snapd-2.0.8/cmd/cmd.go
--- snapd-2.0.5/cmd/cmd.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/cmd/cmd.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,82 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package cmd
+
+import (
+ "os"
+ "path/filepath"
+ "strconv"
+ "syscall"
+
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/release"
+)
+
+// The SNAP_REEXEC environment variable controls whether the command
+// will attempt to re-exec itself from inside an ubuntu-core snap
+// present on the system. If not present in the environ it's assumed
+// to be set to 1 (do re-exec); that is: set it to 0 to disable.
+const key = "SNAP_REEXEC"
+
+// newCore is the place to look for the core snap; everything in this
+// location will be new enough to re-exec into.
+const newCore = "/snap/core/current"
+
+// oldCore is the previous location of the core snap. Only things
+// newer than minOldRevno will be ok to re-exec into.
+const oldCore = "/snap/ubuntu-core/current"
+
+// old ubuntu-core snaps older than this aren't suitable targets for re-execage
+const minOldRevno = 126
+
+// ExecInCoreSnap makes sure you're executing the binary that ships in
+// the core snap.
+func ExecInCoreSnap() {
+ if !release.OnClassic {
+ // you're already the real deal, natch
+ return
+ }
+
+ if os.Getenv(key) == "0" {
+ return
+ }
+
+ exe, err := os.Readlink("/proc/self/exe")
+ if err != nil {
+ return
+ }
+
+ full := filepath.Join(newCore, exe)
+ if !osutil.FileExists(full) {
+ if rev, err := os.Readlink(oldCore); err != nil {
+ return
+ } else if revno, err := strconv.Atoi(rev); err != nil || revno < minOldRevno {
+ return
+ }
+
+ full = filepath.Join(oldCore, exe)
+ if !osutil.FileExists(full) {
+ return
+ }
+ }
+
+ env := append(os.Environ(), key+"=0")
+ panic(syscall.Exec(full, os.Args, env))
+}
diff -Nru snapd-2.0.5/cmd/snap/cmd_abort.go snapd-2.0.8/cmd/snap/cmd_abort.go
--- snapd-2.0.5/cmd/snap/cmd_abort.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_abort.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"github.com/jessevdk/go-flags"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/i18n"
)
type cmdAbort struct {
diff -Nru snapd-2.0.5/cmd/snap/cmd_ack.go snapd-2.0.8/cmd/snap/cmd_ack.go
--- snapd-2.0.5/cmd/snap/cmd_ack.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_ack.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"io/ioutil"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
)
diff -Nru snapd-2.0.5/cmd/snap/cmd_booted.go snapd-2.0.8/cmd/snap/cmd_booted.go
--- snapd-2.0.5/cmd/snap/cmd_booted.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_booted.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,8 +24,8 @@
"github.com/jessevdk/go-flags"
- "github.com/ubuntu-core/snappy/partition"
- "github.com/ubuntu-core/snappy/snappy"
+ "github.com/snapcore/snapd/partition"
+ "github.com/snapcore/snapd/snappy"
)
type cmdBooted struct{}
diff -Nru snapd-2.0.5/cmd/snap/cmd_changes.go snapd-2.0.8/cmd/snap/cmd_changes.go
--- snapd-2.0.5/cmd/snap/cmd_changes.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_changes.go 2016-06-08 05:58:01.000000000 +0000
@@ -21,27 +21,39 @@
import (
"fmt"
+ "os"
+ "regexp"
"sort"
+ "time"
- "github.com/ubuntu-core/snappy/client"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/client"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
- "time"
)
var shortChangesHelp = i18n.G("List system changes")
+var shortChangeHelp = i18n.G("List a change's tasks")
var longChangesHelp = i18n.G(`
The changes command displays a summary of the recent system changes performed.`)
+var longChangeHelp = i18n.G(`
+The change command displays a summary of tasks associated to an individual change.`)
type cmdChanges struct {
Positional struct {
- Id string `positional-arg-name:""`
+ Snap string `positional-arg-name:""`
+ } `positional-args:"yes"`
+}
+
+type cmdChange struct {
+ Positional struct {
+ Id string `positional-arg-name:"" required:"yes"`
} `positional-args:"yes"`
}
func init() {
addCommand("changes", shortChangesHelp, longChangesHelp, func() flags.Commander { return &cmdChanges{} })
+ addCommand("change", shortChangeHelp, longChangeHelp, func() flags.Commander { return &cmdChange{} })
}
type changesByTime []*client.Change
@@ -50,19 +62,26 @@
func (s changesByTime) Less(i, j int) bool { return s[i].SpawnTime.Before(s[j].SpawnTime) }
func (s changesByTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+var allDigits = regexp.MustCompile(`^[0-9]+$`).MatchString
+
func (c *cmdChanges) Execute([]string) error {
- if c.Positional.Id == "everything" {
+ if allDigits(c.Positional.Snap) {
+ return fmt.Errorf(`%s changes command expects a snap name, try: %[1]s change %s`, os.Args[0], c.Positional.Snap)
+ }
+
+ if c.Positional.Snap == "everything" {
fmt.Fprintln(Stdout, "Yes, yes it does.")
return nil
}
- if c.Positional.Id != "" {
- return c.showChange(c.Positional.Id)
+ opts := client.ChangesOptions{
+ SnapName: c.Positional.Snap,
+ Selector: client.ChangesAll,
}
cli := Client()
- changes, err := cli.Changes(client.ChangesAll)
+ changes, err := cli.Changes(&opts)
if err != nil {
return err
}
@@ -91,9 +110,9 @@
return nil
}
-func (c *cmdChanges) showChange(id string) error {
+func (c *cmdChange) Execute([]string) error {
cli := Client()
- chg, err := cli.Change(id)
+ chg, err := cli.Change(c.Positional.Id)
if err != nil {
return err
}
diff -Nru snapd-2.0.5/cmd/snap/cmd_classic.go snapd-2.0.8/cmd/snap/cmd_classic.go
--- snapd-2.0.5/cmd/snap/cmd_classic.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_classic.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,9 +24,9 @@
//"github.com/jessevdk/go-flags"
- "github.com/ubuntu-core/snappy/classic"
- "github.com/ubuntu-core/snappy/i18n"
- "github.com/ubuntu-core/snappy/progress"
+ "github.com/snapcore/snapd/classic"
+ "github.com/snapcore/snapd/i18n"
+ "github.com/snapcore/snapd/progress"
)
// FIXME: Implement feature via "snap install classic"
diff -Nru snapd-2.0.5/cmd/snap/cmd_connect.go snapd-2.0.8/cmd/snap/cmd_connect.go
--- snapd-2.0.5/cmd/snap/cmd_connect.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_connect.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package main
import (
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
)
diff -Nru snapd-2.0.5/cmd/snap/cmd_connect_test.go snapd-2.0.8/cmd/snap/cmd_connect_test.go
--- snapd-2.0.5/cmd/snap/cmd_connect_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_connect_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/cmd/snap"
+ . "github.com/snapcore/snapd/cmd/snap"
)
func (s *SnapSuite) TestConnectHelp(c *C) {
@@ -53,6 +53,9 @@
first of these snaps that has a matching plug name is used and the command
proceeds as above.
+Application Options:
+ --version print the version and exit
+
Help Options:
-h, --help Show this help message
`
diff -Nru snapd-2.0.5/cmd/snap/cmd_disconnect.go snapd-2.0.8/cmd/snap/cmd_disconnect.go
--- snapd-2.0.5/cmd/snap/cmd_disconnect.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_disconnect.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package main
import (
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
)
diff -Nru snapd-2.0.5/cmd/snap/cmd_disconnect_test.go snapd-2.0.8/cmd/snap/cmd_disconnect_test.go
--- snapd-2.0.5/cmd/snap/cmd_disconnect_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_disconnect_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/cmd/snap"
+ . "github.com/snapcore/snapd/cmd/snap"
)
func (s *SnapSuite) TestDisconnectHelp(c *C) {
@@ -48,6 +48,9 @@
Disconnects all plugs from the provided snap.
+Application Options:
+ --version print the version and exit
+
Help Options:
-h, --help Show this help message
`
diff -Nru snapd-2.0.5/cmd/snap/cmd_experimental.go snapd-2.0.8/cmd/snap/cmd_experimental.go
--- snapd-2.0.5/cmd/snap/cmd_experimental.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_experimental.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package main
import (
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/i18n"
)
type cmdExperimental struct{}
diff -Nru snapd-2.0.5/cmd/snap/cmd_find.go snapd-2.0.8/cmd/snap/cmd_find.go
--- snapd-2.0.5/cmd/snap/cmd_find.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_find.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,10 +22,9 @@
import (
"fmt"
"sort"
- "text/tabwriter"
- "github.com/ubuntu-core/snappy/client"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/client"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
)
@@ -38,7 +37,7 @@
func getPrice(prices map[string]float64, currency string) string {
// If there are no prices, then the snap is free
if len(prices) == 0 {
- return "-"
+ return ""
}
// Look up the price by currency code
@@ -76,42 +75,21 @@
})
}
-func hasPrices(snaps []*client.Snap) bool {
- for _, snap := range snaps {
- if len(snap.Prices) > 0 {
- return true
- }
- }
- return false
-}
-
-func printWithPrices(w *tabwriter.Writer, snaps []*client.Snap, suggestedCurrency string) {
- fmt.Fprintln(w, i18n.G("Name\tVersion\tPrice\tSummary"))
-
- for _, snap := range snaps {
- price := getPrice(snap.Prices, suggestedCurrency)
- fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", snap.Name, snap.Version, price, snap.Summary)
-
- }
-}
-
-func printNoPrices(w *tabwriter.Writer, snaps []*client.Snap) {
- fmt.Fprintln(w, i18n.G("Name\tVersion\tSummary"))
-
- for _, snap := range snaps {
- fmt.Fprintf(w, "%s\t%s\t%s\n", snap.Name, snap.Version, snap.Summary)
- }
+func (x *cmdFind) Execute([]string) error {
+ return findSnaps(&client.FindOptions{
+ Query: x.Positional.Query,
+ })
}
-func (x *cmdFind) Execute([]string) error {
+func findSnaps(opts *client.FindOptions) error {
cli := Client()
- snaps, resInfo, err := cli.FindSnaps(x.Positional.Query)
+ snaps, resInfo, err := cli.Find(opts)
if err != nil {
return err
}
if len(snaps) == 0 {
- return fmt.Errorf("no snaps found for %q", x.Positional.Query)
+ return fmt.Errorf("no snaps found for %q", opts.Query)
}
sort.Sort(snapsByName(snaps))
@@ -119,10 +97,16 @@
w := tabWriter()
defer w.Flush()
- if hasPrices(snaps) {
- printWithPrices(w, snaps, resInfo.SuggestedCurrency)
- } else {
- printNoPrices(w, snaps)
+ fmt.Fprintln(w, i18n.G("Name\tVersion\tDeveloper\tNotes\tSummary"))
+
+ for _, snap := range snaps {
+ notes := &Notes{
+ Private: snap.Private,
+ Confinement: snap.Confinement,
+ Price: getPrice(snap.Prices, resInfo.SuggestedCurrency),
+ }
+ // TODO: get snap.Publisher, so we can only show snap.Developer if it's different
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", snap.Name, snap.Version, snap.Developer, notes, snap.Summary)
}
return nil
diff -Nru snapd-2.0.5/cmd/snap/cmd_first_boot.go snapd-2.0.8/cmd/snap/cmd_first_boot.go
--- snapd-2.0.5/cmd/snap/cmd_first_boot.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_first_boot.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"github.com/jessevdk/go-flags"
- "github.com/ubuntu-core/snappy/overlord"
+ "github.com/snapcore/snapd/overlord"
)
type cmdInternalFirstBoot struct{}
diff -Nru snapd-2.0.5/cmd/snap/cmd_help.go snapd-2.0.8/cmd/snap/cmd_help.go
--- snapd-2.0.5/cmd/snap/cmd_help.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_help.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"os"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
)
diff -Nru snapd-2.0.5/cmd/snap/cmd_help_test.go snapd-2.0.8/cmd/snap/cmd_help_test.go
--- snapd-2.0.5/cmd/snap/cmd_help_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_help_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,7 +25,7 @@
"gopkg.in/check.v1"
- snap "github.com/ubuntu-core/snappy/cmd/snap"
+ snap "github.com/snapcore/snapd/cmd/snap"
)
func (s *SnapSuite) TestHelpPrintsHelp(c *check.C) {
@@ -48,6 +48,9 @@
platform.
+Application Options:
+ +--version +print the version and exit
+
Help Options:
+-h, --help +Show this help message
diff -Nru snapd-2.0.5/cmd/snap/cmd_interfaces.go snapd-2.0.8/cmd/snap/cmd_interfaces.go
--- snapd-2.0.5/cmd/snap/cmd_interfaces.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_interfaces.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"fmt"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
)
diff -Nru snapd-2.0.5/cmd/snap/cmd_interfaces_test.go snapd-2.0.8/cmd/snap/cmd_interfaces_test.go
--- snapd-2.0.5/cmd/snap/cmd_interfaces_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_interfaces_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/client"
- . "github.com/ubuntu-core/snappy/cmd/snap"
+ "github.com/snapcore/snapd/client"
+ . "github.com/snapcore/snapd/cmd/snap"
)
func (s *SnapSuite) TestInterfacesHelp(c *C) {
@@ -51,6 +51,9 @@
Filters the complete output so only plugs and/or slots matching the provided
details are listed.
+Application Options:
+ --version print the version and exit
+
Help Options:
-h, --help Show this help message
diff -Nru snapd-2.0.5/cmd/snap/cmd_known.go snapd-2.0.8/cmd/snap/cmd_known.go
--- snapd-2.0.5/cmd/snap/cmd_known.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_known.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,8 +23,8 @@
"fmt"
"strings"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
)
diff -Nru snapd-2.0.5/cmd/snap/cmd_list.go snapd-2.0.8/cmd/snap/cmd_list.go
--- snapd-2.0.5/cmd/snap/cmd_list.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_list.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,11 +22,10 @@
import (
"fmt"
"sort"
- "strconv"
"text/tabwriter"
- "github.com/ubuntu-core/snappy/client"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/client"
+ "github.com/snapcore/snapd/i18n"
"github.com/jessevdk/go-flags"
)
@@ -55,22 +54,29 @@
return listSnaps(x.Positional.Snaps)
}
-func listSnaps(args []string) error {
+func listSnaps(names []string) error {
cli := Client()
- snaps, err := cli.ListSnaps(args)
+ snaps, err := cli.List(names)
if err != nil {
return err
+ } else if len(snaps) == 0 {
+ fmt.Fprintln(Stderr, i18n.G("No snaps are installed yet. Try 'snap install hello-world'."))
+ return nil
}
-
sort.Sort(snapsByName(snaps))
w := tabWriter()
defer w.Flush()
- fmt.Fprintln(w, i18n.G("Name\tVersion\tRev\tDeveloper"))
+ fmt.Fprintln(w, i18n.G("Name\tVersion\tRev\tDeveloper\tNotes"))
for _, snap := range snaps {
- fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", snap.Name, snap.Version, strconv.Itoa(snap.Revision), snap.Developer)
+ notes := &Notes{
+ Private: snap.Private,
+ DevMode: snap.DevMode,
+ TryMode: snap.TryMode,
+ }
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", snap.Name, snap.Version, snap.Revision, snap.Developer, notes)
}
return nil
diff -Nru snapd-2.0.5/cmd/snap/cmd_list_test.go snapd-2.0.8/cmd/snap/cmd_list_test.go
--- snapd-2.0.5/cmd/snap/cmd_list_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_list_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
"gopkg.in/check.v1"
- snap "github.com/ubuntu-core/snappy/cmd/snap"
+ snap "github.com/snapcore/snapd/cmd/snap"
)
func (s *SnapSuite) TestList(c *check.C) {
@@ -46,12 +46,33 @@
rest, err := snap.Parser().ParseArgs([]string{"list"})
c.Assert(err, check.IsNil)
c.Assert(rest, check.DeepEquals, []string{})
- c.Check(s.Stdout(), check.Matches, `Name +Version +Rev +Developer
-foo +4.2 +17 +bar
+ c.Check(s.Stdout(), check.Matches, `Name +Version +Rev +Developer +Notes
+foo +4.2 +17 +bar +-
`)
c.Check(s.Stderr(), check.Equals, "")
}
+func (s *SnapSuite) TestListEmpty(c *check.C) {
+ n := 0
+ s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
+ switch n {
+ case 0:
+ c.Check(r.Method, check.Equals, "GET")
+ c.Check(r.URL.Path, check.Equals, "/v2/snaps")
+ fmt.Fprintln(w, `{"type": "sync", "result": []}`)
+ default:
+ c.Fatalf("expected to get 1 requests, now on %d", n+1)
+ }
+
+ n++
+ })
+ rest, err := snap.Parser().ParseArgs([]string{"list"})
+ c.Assert(err, check.IsNil)
+ c.Assert(rest, check.DeepEquals, []string{})
+ c.Check(s.Stdout(), check.Equals, "")
+ c.Check(s.Stderr(), check.Matches, "No snaps are installed yet. Try 'snap install hello-world'.\n")
+}
+
func (s *SnapSuite) TestListWithQuery(c *check.C) {
n := 0
s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
@@ -70,10 +91,33 @@
rest, err := snap.Parser().ParseArgs([]string{"list", "foo"})
c.Assert(err, check.IsNil)
c.Assert(rest, check.DeepEquals, []string{})
- c.Check(s.Stdout(), check.Matches, `Name +Version +Rev +Developer
-foo +4.2 +17 +bar
+ c.Check(s.Stdout(), check.Matches, `Name +Version +Rev +Developer +Notes
+foo +4.2 +17 +bar +-
`)
c.Check(s.Stderr(), check.Equals, "")
// ensure that the fake server api was actually hit
c.Check(n, check.Equals, 1)
}
+
+func (s *SnapSuite) TestListWithNotes(c *check.C) {
+ n := 0
+ s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
+ switch n {
+ case 0:
+ c.Check(r.Method, check.Equals, "GET")
+ c.Check(r.URL.Path, check.Equals, "/v2/snaps")
+ fmt.Fprintln(w, `{"type": "sync", "result": [{"name": "foo", "status": "active", "version": "4.2", "developer": "bar", "revision":17, "trymode": true}]}`)
+ default:
+ c.Fatalf("expected to get 1 requests, now on %d", n+1)
+ }
+
+ n++
+ })
+ rest, err := snap.Parser().ParseArgs([]string{"list"})
+ c.Assert(err, check.IsNil)
+ c.Assert(rest, check.DeepEquals, []string{})
+ c.Check(s.Stdout(), check.Matches, `Name +Version +Rev +Developer +Notes
+foo +4.2 +17 +bar +try
+`)
+ c.Check(s.Stderr(), check.Equals, "")
+}
diff -Nru snapd-2.0.5/cmd/snap/cmd_login.go snapd-2.0.8/cmd/snap/cmd_login.go
--- snapd-2.0.5/cmd/snap/cmd_login.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_login.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
"github.com/jessevdk/go-flags"
"golang.org/x/crypto/ssh/terminal"
- "github.com/ubuntu-core/snappy/client"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/client"
+ "github.com/snapcore/snapd/i18n"
)
type cmdLogin struct {
diff -Nru snapd-2.0.5/cmd/snap/cmd_logout.go snapd-2.0.8/cmd/snap/cmd_logout.go
--- snapd-2.0.5/cmd/snap/cmd_logout.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_logout.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"github.com/jessevdk/go-flags"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/i18n"
)
type cmdLogout struct{}
diff -Nru snapd-2.0.5/cmd/snap/cmd_shell.go snapd-2.0.8/cmd/snap/cmd_shell.go
--- snapd-2.0.5/cmd/snap/cmd_shell.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_shell.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
//"github.com/jessevdk/go-flags"
- "github.com/ubuntu-core/snappy/classic"
- "github.com/ubuntu-core/snappy/i18n"
+ "github.com/snapcore/snapd/classic"
+ "github.com/snapcore/snapd/i18n"
)
type cmdShell struct {
diff -Nru snapd-2.0.5/cmd/snap/cmd_snap_op.go snapd-2.0.8/cmd/snap/cmd_snap_op.go
--- snapd-2.0.5/cmd/snap/cmd_snap_op.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_snap_op.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,12 +22,13 @@
import (
"errors"
"fmt"
+ "path/filepath"
"strings"
"time"
- "github.com/ubuntu-core/snappy/client"
- "github.com/ubuntu-core/snappy/i18n"
- "github.com/ubuntu-core/snappy/progress"
+ "github.com/snapcore/snapd/client"
+ "github.com/snapcore/snapd/i18n"
+ "github.com/snapcore/snapd/progress"
"github.com/jessevdk/go-flags"
)
@@ -97,6 +98,7 @@
shortInstallHelp = i18n.G("Install a snap to the system")
shortRemoveHelp = i18n.G("Remove a snap from the system")
shortRefreshHelp = i18n.G("Refresh a snap in the system")
+ shortTryHelp = i18n.G("Try an unpacked snap in the system")
)
var longInstallHelp = i18n.G(`
@@ -114,6 +116,13 @@
The refresh command refreshes (updates) the named snap.
`)
+var longTryHelp = i18n.G(`
+The try command installs an unpacked snap into the system for testing purposes.
+The unpacked snap content continues to be used even after installation, so
+non-metadata changes there go live instantly. Metadata changes such as those
+performed in snap.yaml will require reinstallation to go live.
+`)
+
type cmdRemove struct {
Positional struct {
Snap string `positional-arg-name:""`
@@ -180,17 +189,37 @@
}
type cmdRefresh struct {
+ List bool `long:"list" description:"show available snaps for refresh"`
Channel string `long:"channel" description:"Refresh to the latest on this channel, and track this channel henceforth"`
Positional struct {
Snap string `positional-arg-name:""`
- } `positional-args:"yes" required:"yes"`
+ } `positional-args:"yes"`
}
-func (x *cmdRefresh) Execute([]string) error {
+func refreshAll() error {
+ // FIXME: move this to snapd instead and have a new refresh-all endpoint
cli := Client()
- name := x.Positional.Snap
- opts := &client.SnapOptions{Channel: x.Channel}
- changeID, err := cli.Refresh(name, opts)
+ updates, _, err := cli.Find(&client.FindOptions{Refresh: true})
+ if err != nil {
+ return fmt.Errorf("cannot list updates: %s", err)
+ }
+
+ for _, update := range updates {
+ changeID, err := cli.Refresh(update.Name, &client.SnapOptions{Channel: update.Channel})
+ if err != nil {
+ return err
+ }
+ if _, err := wait(cli, changeID); err != nil {
+ return err
+ }
+ }
+
+ return listSnaps(nil)
+}
+
+func refreshOne(name, channel string) error {
+ cli := Client()
+ changeID, err := cli.Refresh(name, &client.SnapOptions{Channel: channel})
if err != nil {
return err
}
@@ -198,6 +227,58 @@
if _, err := wait(cli, changeID); err != nil {
return err
}
+
+ return listSnaps([]string{name})
+}
+
+func (x *cmdRefresh) Execute([]string) error {
+ if x.List {
+ return findSnaps(&client.FindOptions{
+ Refresh: true,
+ })
+ }
+ if x.Positional.Snap == "" {
+ return refreshAll()
+ }
+ return refreshOne(x.Positional.Snap, x.Channel)
+}
+
+type cmdTry struct {
+ DevMode bool `long:"devmode" description:"Install in development mode and disable confinement"`
+ Positional struct {
+ SnapDir string `positional-arg-name:""`
+ } `positional-args:"yes" required:"yes"`
+}
+
+func (x *cmdTry) Execute([]string) error {
+ cli := Client()
+ name := x.Positional.SnapDir
+ opts := &client.SnapOptions{
+ DevMode: x.DevMode,
+ }
+
+ path, err := filepath.Abs(name)
+ if err != nil {
+ return fmt.Errorf("cannot get full path for %q: %s", name, err)
+ }
+
+ changeID, err := cli.Try(path, opts)
+ if err != nil {
+ return err
+ }
+
+ chg, err := wait(cli, changeID)
+ if err != nil {
+ return err
+ }
+
+ // extract the snap name
+ var snapName string
+ if err := chg.Get("snap-name", &snapName); err != nil {
+ return fmt.Errorf("cannot extract the snap-name from local file %q: %s", name, err)
+ }
+ name = snapName
+
return listSnaps([]string{name})
}
@@ -205,4 +286,5 @@
addCommand("remove", shortRemoveHelp, longRemoveHelp, func() flags.Commander { return &cmdRemove{} })
addCommand("install", shortInstallHelp, longInstallHelp, func() flags.Commander { return &cmdInstall{} })
addCommand("refresh", shortRefreshHelp, longRefreshHelp, func() flags.Commander { return &cmdRefresh{} })
+ addCommand("try", shortTryHelp, longTryHelp, func() flags.Commander { return &cmdTry{} })
}
diff -Nru snapd-2.0.5/cmd/snap/cmd_snap_op_test.go snapd-2.0.8/cmd/snap/cmd_snap_op_test.go
--- snapd-2.0.5/cmd/snap/cmd_snap_op_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/cmd_snap_op_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,10 +25,12 @@
"io/ioutil"
"net/http"
"path/filepath"
+ "regexp"
+ "strconv"
"gopkg.in/check.v1"
- snap "github.com/ubuntu-core/snappy/cmd/snap"
+ snap "github.com/snapcore/snapd/cmd/snap"
)
type snapOpTestServer struct {
@@ -39,6 +41,8 @@
total int
}
+var _ = check.Suite(&SnapOpSuite{})
+
func (t *snapOpTestServer) handle(w http.ResponseWriter, r *http.Request) {
switch t.n {
case 0:
@@ -53,13 +57,9 @@
case 2:
t.c.Check(r.Method, check.Equals, "GET")
t.c.Check(r.URL.Path, check.Equals, "/v2/changes/42")
- fmt.Fprintln(w, `{"type": "sync", "result": {"ready": true, "status": "Done"}}`)
+ fmt.Fprintln(w, `{"type": "sync", "result": {"ready": true, "status": "Done", "data": {"snap-name": "foo"}}}`)
case 3:
t.c.Check(r.Method, check.Equals, "GET")
- t.c.Check(r.URL.Path, check.Equals, "/v2/changes/42")
- fmt.Fprintln(w, `{"type": "sync", "result": {"ready": true, "status": "Done"}}`)
- case 4:
- t.c.Check(r.Method, check.Equals, "GET")
t.c.Check(r.URL.Path, check.Equals, "/v2/snaps")
fmt.Fprintln(w, `{"type": "sync", "result": [{"name": "foo", "status": "active", "version": "1.0", "developer": "bar", "revision":42}]}`)
default:
@@ -75,25 +75,27 @@
srv snapOpTestServer
}
-func (s *SnapOpSuite) SetupTest(c *check.C) {
+func (s *SnapOpSuite) SetUpTest(c *check.C) {
+ s.SnapSuite.SetUpTest(c)
+
s.srv = snapOpTestServer{
c: c,
- total: 5,
+ total: 4,
}
}
func (s *SnapOpSuite) TestInstall(c *check.C) {
s.srv.checker = func(r *http.Request) {
- c.Check(r.URL.Path, check.Equals, "/v2/snaps/foo.bar")
+ c.Check(r.URL.Path, check.Equals, "/v2/snaps/foo")
c.Check(DecodedRequestBody(c, r), check.DeepEquals, map[string]interface{}{
"action": "install",
- "name": "foo.bar",
+ "name": "foo",
"channel": "chan",
})
}
s.RedirectClientToTestServer(s.srv.handle)
- rest, err := snap.Parser().ParseArgs([]string{"install", "--channel", "chan", "foo.bar"})
+ rest, err := snap.Parser().ParseArgs([]string{"install", "--channel", "chan", "foo"})
c.Assert(err, check.IsNil)
c.Assert(rest, check.DeepEquals, []string{})
c.Check(s.Stdout(), check.Matches, `(?sm).*foo\s+1.0\s+42\s+bar.*`)
@@ -104,17 +106,17 @@
func (s *SnapOpSuite) TestInstallDevMode(c *check.C) {
s.srv.checker = func(r *http.Request) {
- c.Check(r.URL.Path, check.Equals, "/v2/snaps/foo.bar")
+ c.Check(r.URL.Path, check.Equals, "/v2/snaps/foo")
c.Check(DecodedRequestBody(c, r), check.DeepEquals, map[string]interface{}{
"action": "install",
- "name": "foo.bar",
+ "name": "foo",
"devmode": true,
"channel": "chan",
})
}
s.RedirectClientToTestServer(s.srv.handle)
- rest, err := snap.Parser().ParseArgs([]string{"install", "--channel", "chan", "--devmode", "foo.bar"})
+ rest, err := snap.Parser().ParseArgs([]string{"install", "--channel", "chan", "--devmode", "foo"})
c.Assert(err, check.IsNil)
c.Assert(rest, check.DeepEquals, []string{})
c.Check(s.Stdout(), check.Matches, `(?sm).*foo\s+1.0\s+42\s+bar.*`)
@@ -172,3 +174,69 @@
// ensure that the fake server api was actually hit
c.Check(s.srv.n, check.Equals, s.srv.total)
}
+
+func (s *SnapSuite) TestRefreshList(c *check.C) {
+ n := 0
+ s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
+ switch n {
+ case 0:
+ c.Check(r.Method, check.Equals, "GET")
+ c.Check(r.URL.Path, check.Equals, "/v2/find")
+ c.Check(r.URL.Query().Get("select"), check.Equals, "refresh")
+ fmt.Fprintln(w, `{"type": "sync", "result": [{"name": "foo", "status": "active", "version": "4.2update1", "developer": "bar", "revision":17,"summary":"some summary"}]}`)
+ default:
+ c.Fatalf("expected to get 1 requests, now on %d", n+1)
+ }
+
+ n++
+ })
+ rest, err := snap.Parser().ParseArgs([]string{"refresh", "--list"})
+ c.Assert(err, check.IsNil)
+ c.Assert(rest, check.DeepEquals, []string{})
+ c.Check(s.Stdout(), check.Matches, `Name +Version +Developer +Notes +Summary
+foo +4.2update1 +bar +- +some summary
+`)
+ c.Check(s.Stderr(), check.Equals, "")
+ // ensure that the fake server api was actually hit
+ c.Check(n, check.Equals, 1)
+}
+
+func (s *SnapOpSuite) runTryTest(c *check.C, devmode bool) {
+ // pass relative path to cmd
+ tryDir := "some-dir"
+
+ s.srv.checker = func(r *http.Request) {
+ // ensure the client always sends the absolute path
+ fullTryDir, err := filepath.Abs(tryDir)
+ c.Assert(err, check.IsNil)
+
+ c.Check(r.URL.Path, check.Equals, "/v2/snaps")
+ postData, err := ioutil.ReadAll(r.Body)
+ c.Assert(err, check.IsNil)
+ c.Assert(string(postData), check.Matches, "(?s).*Content-Disposition: form-data; name=\"action\"\r\n\r\ntry\r\n.*")
+ c.Assert(string(postData), check.Matches, fmt.Sprintf("(?s).*Content-Disposition: form-data; name=\"snap-path\"\r\n\r\n%s\r\n.*", regexp.QuoteMeta(fullTryDir)))
+ c.Assert(string(postData), check.Matches, fmt.Sprintf("(?s).*Content-Disposition: form-data; name=\"devmode\"\r\n\r\n%s\r\n.*", strconv.FormatBool(devmode)))
+ }
+
+ s.RedirectClientToTestServer(s.srv.handle)
+
+ cmd := []string{"try", tryDir}
+ if devmode {
+ cmd = append(cmd, "--devmode")
+ }
+
+ rest, err := snap.Parser().ParseArgs(cmd)
+ c.Assert(err, check.IsNil)
+ c.Assert(rest, check.DeepEquals, []string{})
+ c.Check(s.Stdout(), check.Matches, `(?sm).*foo\s+1.0\s+42\s+bar.*`)
+ c.Check(s.Stderr(), check.Equals, "")
+ // ensure that the fake server api was actually hit
+ c.Check(s.srv.n, check.Equals, s.srv.total)
+}
+
+func (s *SnapOpSuite) TestTryNoDevMode(c *check.C) {
+ s.runTryTest(c, false)
+}
+func (s *SnapOpSuite) TestTryDevMode(c *check.C) {
+ s.runTryTest(c, true)
+}
diff -Nru snapd-2.0.5/cmd/snap/integration_coverage_test.go snapd-2.0.8/cmd/snap/integration_coverage_test.go
--- snapd-2.0.5/cmd/snap/integration_coverage_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/integration_coverage_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,7 +23,7 @@
import (
"testing"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/testutils"
+ "github.com/snapcore/snapd/integration-tests/testutils/testutils"
)
func TestRunMain(t *testing.T) {
diff -Nru snapd-2.0.5/cmd/snap/interfaces_common_test.go snapd-2.0.8/cmd/snap/interfaces_common_test.go
--- snapd-2.0.5/cmd/snap/interfaces_common_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/interfaces_common_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,7 +23,7 @@
import (
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/cmd/snap"
+ . "github.com/snapcore/snapd/cmd/snap"
)
type AttributePairSuite struct{}
diff -Nru snapd-2.0.5/cmd/snap/main.go snapd-2.0.8/cmd/snap/main.go
--- snapd-2.0.5/cmd/snap/main.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/main.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,8 +25,10 @@
"os"
"strings"
- "github.com/ubuntu-core/snappy/client"
- "github.com/ubuntu-core/snappy/logger"
+ "github.com/snapcore/snapd/client"
+ "github.com/snapcore/snapd/cmd"
+ "github.com/snapcore/snapd/i18n"
+ "github.com/snapcore/snapd/logger"
"github.com/jessevdk/go-flags"
)
@@ -39,7 +41,7 @@
)
type options struct {
- // No global options yet
+ Version func() `long:"version" description:"print the version and exit"`
}
var optionsData options
@@ -92,6 +94,16 @@
// Since commands have local state a fresh parser is required to isolate tests
// from each other.
func Parser() *flags.Parser {
+ optionsData.Version = func() {
+ cv, err := Client().ServerVersion()
+ if err != nil {
+ cv = i18n.G("unavailable")
+ }
+
+ fmt.Fprintf(Stdout, "snap %s\nsnapd %s\n", cmd.Version, cv)
+
+ os.Exit(0)
+ }
parser := flags.NewParser(&optionsData, flags.HelpFlag|flags.PassDoubleDash)
parser.ShortDescription = "Tool to interact with snaps"
parser.LongDescription = `
@@ -145,6 +157,7 @@
}
func main() {
+ cmd.ExecInCoreSnap()
if err := run(); err != nil {
fmt.Fprintf(Stderr, "error: %v\n", err)
os.Exit(1)
diff -Nru snapd-2.0.5/cmd/snap/main_test.go snapd-2.0.8/cmd/snap/main_test.go
--- snapd-2.0.5/cmd/snap/main_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snap/main_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -31,9 +31,9 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/testutil"
- snap "github.com/ubuntu-core/snappy/cmd/snap"
+ snap "github.com/snapcore/snapd/cmd/snap"
)
// Hook up check.v1 into the "go test" runner
diff -Nru snapd-2.0.5/cmd/snap/notes.go snapd-2.0.8/cmd/snap/notes.go
--- snapd-2.0.5/cmd/snap/notes.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/cmd/snap/notes.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,64 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package main
+
+import (
+ "strings"
+
+ "github.com/snapcore/snapd/client"
+)
+
+type Notes struct {
+ Confinement string
+ Price string
+ Private bool
+ DevMode bool
+ TryMode bool
+}
+
+func (n *Notes) String() string {
+ var ns []string
+
+ if n.Price != "" {
+ ns = append(ns, n.Price)
+ }
+
+ if n.Confinement != "" {
+ if n.Confinement != client.StrictConfinement {
+ ns = append(ns, n.Confinement)
+ }
+ } else if n.DevMode {
+ ns = append(ns, "devmode")
+ }
+
+ if n.Private {
+ ns = append(ns, "private")
+ }
+
+ if n.TryMode {
+ ns = append(ns, "try")
+ }
+
+ if len(ns) == 0 {
+ return "-"
+ }
+
+ return strings.Join(ns, ",")
+}
diff -Nru snapd-2.0.5/cmd/snap/notes_test.go snapd-2.0.8/cmd/snap/notes_test.go
--- snapd-2.0.5/cmd/snap/notes_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/cmd/snap/notes_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,61 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !integrationcoverage
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package main_test
+
+import (
+ "gopkg.in/check.v1"
+
+ snap "github.com/snapcore/snapd/cmd/snap"
+)
+
+type notesSuite struct{}
+
+var _ = check.Suite(¬esSuite{})
+
+func (notesSuite) TestNoNotes(c *check.C) {
+ c.Check((&snap.Notes{}).String(), check.Equals, "-")
+}
+
+func (notesSuite) TestNotesPrice(c *check.C) {
+ c.Check((&snap.Notes{
+ Price: "3.50GBP",
+ }).String(), check.Equals, "3.50GBP")
+}
+
+func (notesSuite) TestNotesPrivate(c *check.C) {
+ c.Check((&snap.Notes{
+ Private: true,
+ }).String(), check.Equals, "private")
+}
+
+func (notesSuite) TestNotesPrivateDevmode(c *check.C) {
+ c.Check((&snap.Notes{
+ Private: true,
+ Confinement: "devmode",
+ }).String(), check.Equals, "devmode,private")
+}
+
+func (notesSuite) TestNotesOtherDevmode(c *check.C) {
+ c.Check((&snap.Notes{
+ DevMode: true,
+ TryMode: true,
+ }).String(), check.Equals, "devmode,try")
+}
diff -Nru snapd-2.0.5/cmd/snapd/integration_coverage_test.go snapd-2.0.8/cmd/snapd/integration_coverage_test.go
--- snapd-2.0.5/cmd/snapd/integration_coverage_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snapd/integration_coverage_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,7 +23,7 @@
import (
"testing"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/testutils"
+ "github.com/snapcore/snapd/integration-tests/testutils/testutils"
)
func TestRunMain(t *testing.T) {
diff -Nru snapd-2.0.5/cmd/snapd/main.go snapd-2.0.8/cmd/snapd/main.go
--- snapd-2.0.5/cmd/snapd/main.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/cmd/snapd/main.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,8 +25,9 @@
"os/signal"
"syscall"
- "github.com/ubuntu-core/snappy/daemon"
- "github.com/ubuntu-core/snappy/logger"
+ "github.com/snapcore/snapd/cmd"
+ "github.com/snapcore/snapd/daemon"
+ "github.com/snapcore/snapd/logger"
)
func init() {
@@ -37,6 +38,7 @@
}
func main() {
+ cmd.ExecInCoreSnap()
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
@@ -48,10 +50,10 @@
if err != nil {
return err
}
-
if err := d.Init(); err != nil {
return err
}
+ d.Version = cmd.Version
d.Start()
diff -Nru snapd-2.0.5/cmd/snap-exec/main.go snapd-2.0.8/cmd/snap-exec/main.go
--- snapd-2.0.5/cmd/snap-exec/main.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/cmd/snap-exec/main.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,116 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2015 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "syscall"
+
+ "github.com/jessevdk/go-flags"
+
+ "github.com/snapcore/snapd/snap"
+)
+
+// for the tests
+var syscallExec = syscall.Exec
+
+func main() {
+ if err := run(); err != nil {
+ fmt.Printf("cannot snap-exec: %s\n", err)
+ os.Exit(1)
+ }
+}
+
+func run() error {
+ var opts struct {
+ Positional struct {
+ SnapApp string `positional-arg-name:"" description:"the application to run, e.g. hello-world.env"`
+ } `positional-args:"yes" required:"yes"`
+
+ Command string `long:"command" description:"use a different command like {stop,post-stop} from the app"`
+ }
+
+ parser := flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash)
+ args, err := parser.Parse()
+ if err != nil {
+ return err
+ }
+
+ // the SNAP_REVISION is set by `snap run` - we can not (easily)
+ // find it in `snap-exec` because `snap-exec` is run inside the
+ // confinement and (generally) can not talk to snapd
+ revision := os.Getenv("SNAP_REVISION")
+
+ snapApp := opts.Positional.SnapApp
+ return snapExec(snapApp, revision, opts.Command, args)
+}
+
+func findCommand(app *snap.AppInfo, command string) (string, error) {
+ var cmd string
+ switch command {
+ case "stop":
+ cmd = app.StopCommand
+ case "post-stop":
+ cmd = app.PostStopCommand
+ case "":
+ cmd = app.Command
+ default:
+ return "", fmt.Errorf("cannot use %q command", command)
+ }
+
+ if cmd == "" {
+ return "", fmt.Errorf("no %q command found for %q", command, app.Name)
+ }
+ return cmd, nil
+}
+
+func snapExec(snapApp, revision, command string, args []string) error {
+ rev, err := snap.ParseRevision(revision)
+ if err != nil {
+ return err
+ }
+
+ snapName, appName := snap.SplitSnapApp(snapApp)
+ info, err := snap.ReadInfo(snapName, &snap.SideInfo{
+ Revision: rev,
+ })
+ if err != nil {
+ return err
+ }
+
+ app := info.Apps[appName]
+ if app == nil {
+ return fmt.Errorf("cannot find app %q in %q", appName, snapName)
+ }
+
+ cmd, err := findCommand(app, command)
+ if err != nil {
+ return err
+ }
+
+ // build the evnironment from the yamle
+ env := append(os.Environ(), app.Env()...)
+
+ // run the command
+ fullCmd := filepath.Join(app.Snap.MountDir(), cmd)
+ return syscallExec(fullCmd, args, env)
+}
diff -Nru snapd-2.0.5/cmd/snap-exec/main_test.go snapd-2.0.8/cmd/snap-exec/main_test.go
--- snapd-2.0.5/cmd/snap-exec/main_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/cmd/snap-exec/main_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,118 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !integrationcoverage
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package main
+
+import (
+ "fmt"
+ "syscall"
+ "testing"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/testutil"
+)
+
+// Hook up check.v1 into the "go test" runner
+func Test(t *testing.T) { TestingT(t) }
+
+type snapExecSuite struct {
+}
+
+var _ = Suite(&snapExecSuite{})
+
+func (s *snapExecSuite) TearDown(c *C) {
+ syscallExec = syscall.Exec
+ dirs.SetRootDir("/")
+}
+
+var mockYaml = []byte(`name: snapname
+version: 1.0
+apps:
+ app:
+ command: run-app
+ stop-command: stop-app
+ post-stop-command: post-stop-app
+ environment:
+ LD_LIBRARY_PATH: /some/path
+ nostop:
+ command: nostop
+`)
+
+func (s *snapExecSuite) TestFindCommand(c *C) {
+ info, err := snap.InfoFromSnapYaml(mockYaml)
+ c.Assert(err, IsNil)
+
+ for _, t := range []struct {
+ cmd string
+ expected string
+ }{
+ {cmd: "", expected: "run-app"},
+ {cmd: "stop", expected: "stop-app"},
+ {cmd: "post-stop", expected: "post-stop-app"},
+ } {
+ cmd, err := findCommand(info.Apps["app"], t.cmd)
+ c.Check(err, IsNil)
+ c.Check(cmd, Equals, t.expected)
+ }
+}
+
+func (s *snapExecSuite) TestFindCommandInvalidCommand(c *C) {
+ info, err := snap.InfoFromSnapYaml(mockYaml)
+ c.Assert(err, IsNil)
+
+ _, err = findCommand(info.Apps["app"], "xxx")
+ c.Check(err, ErrorMatches, `cannot use "xxx" command`)
+}
+
+func (s *snapExecSuite) TestFindCommandNoCommand(c *C) {
+ info, err := snap.InfoFromSnapYaml(mockYaml)
+ c.Assert(err, IsNil)
+
+ _, err = findCommand(info.Apps["nostop"], "stop")
+ c.Check(err, ErrorMatches, `no "stop" command found for "nostop"`)
+}
+
+func (s *snapExecSuite) TestSnapLaunchIntegration(c *C) {
+ dirs.SetRootDir(c.MkDir())
+ snaptest.MockSnap(c, string(mockYaml), &snap.SideInfo{
+ Revision: snap.R("42"),
+ })
+
+ execArgv0 := ""
+ execArgs := []string{}
+ execEnv := []string{}
+ syscallExec = func(argv0 string, argv []string, env []string) error {
+ execArgv0 = argv0
+ execArgs = argv
+ execEnv = env
+ return nil
+ }
+
+ // launch and verify its run the right way
+ err := snapExec("snapname.app", "42", "stop", []string{"arg1", "arg2"})
+ c.Assert(err, IsNil)
+ c.Check(execArgv0, Equals, fmt.Sprintf("%s/snapname/42/stop-app", dirs.SnapSnapsDir))
+ c.Check(execArgs, DeepEquals, []string{"arg1", "arg2"})
+ c.Check(execEnv, testutil.Contains, "LD_LIBRARY_PATH=/some/path\n")
+}
diff -Nru snapd-2.0.5/cmd/version.go snapd-2.0.8/cmd/version.go
--- snapd-2.0.5/cmd/version.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/cmd/version.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,25 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package cmd
+
+//go:generate mkversion.sh
+
+// will be overwritten at build-time via mkversion.sh
+var Version = "unknown"
diff -Nru snapd-2.0.5/coreconfig/config.go snapd-2.0.8/coreconfig/config.go
--- snapd-2.0.5/coreconfig/config.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/coreconfig/config.go 2016-06-08 05:58:01.000000000 +0000
@@ -32,8 +32,8 @@
"strings"
"syscall"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/systemd"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/systemd"
"gopkg.in/yaml.v2"
)
diff -Nru snapd-2.0.5/coreconfig/config_test.go snapd-2.0.8/coreconfig/config_test.go
--- snapd-2.0.5/coreconfig/config_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/coreconfig/config_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
"path/filepath"
"testing"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/systemd"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/systemd"
. "gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/daemon/api.go snapd-2.0.8/daemon/api.go
--- snapd-2.0.5/daemon/api.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/daemon/api.go 2016-06-08 05:58:01.000000000 +0000
@@ -35,20 +35,20 @@
"github.com/gorilla/mux"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/i18n"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/overlord/auth"
- "github.com/ubuntu-core/snappy/overlord/ifacestate"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/release"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snappy"
- "github.com/ubuntu-core/snappy/store"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/i18n"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/overlord/auth"
+ "github.com/snapcore/snapd/overlord/ifacestate"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/store"
)
var api = []*Command{
@@ -173,7 +173,8 @@
func sysInfo(c *Command, r *http.Request, user *auth.UserState) Response {
m := map[string]string{
- "series": release.Series,
+ "series": release.Series,
+ "version": c.d.Version,
}
return SyncResponse(m, nil)
@@ -293,16 +294,6 @@
return user, err
}
-type metarepo interface {
- Snap(string, string, store.Authenticator) (*snap.Info, error)
- FindSnaps(string, string, store.Authenticator) ([]*snap.Info, error)
- SuggestedCurrency() string
-}
-
-var newRemoteRepo = func() metarepo {
- return snappy.NewConfiguredUbuntuStoreSnapRepository()
-}
-
var muxVars = mux.Vars
func getSnapInfo(c *Command, r *http.Request, user *auth.UserState) Response {
@@ -354,47 +345,41 @@
return result
}
+func getStore(c *Command) snapstate.StoreService {
+ return c.d.overlord.SnapManager().Store()
+}
+
func searchStore(c *Command, r *http.Request, user *auth.UserState) Response {
route := c.d.router.Get(snapCmd.Path)
if route == nil {
return InternalError("cannot find route for snaps")
}
-
query := r.URL.Query()
+ if query.Get("select") == "refresh" {
+ if query.Get("q") != "" {
+ return BadRequest("cannot use 'q' with 'select=refresh'")
+ }
+ return storeUpdates(c, r, user)
+ }
+
auther, err := c.d.auther(r)
if err != nil && err != auth.ErrInvalidAuth {
return InternalError("%v", err)
}
- remoteRepo := newRemoteRepo()
- found, err := remoteRepo.FindSnaps(query.Get("q"), query.Get("channel"), auther)
+ store := getStore(c)
+ found, err := store.Find(query.Get("q"), query.Get("channel"), auther)
if err != nil {
return InternalError("%v", err)
}
meta := &Meta{
- SuggestedCurrency: remoteRepo.SuggestedCurrency(),
+ SuggestedCurrency: store.SuggestedCurrency(),
Sources: []string{"store"},
}
- results := make([]*json.RawMessage, len(found))
- for i, x := range found {
- url, err := route.URL("name", x.Name())
- if err != nil {
- logger.Noticef("cannot build URL for snap %q (r%d): %v", x.Name(), x.Revision, err)
- continue
- }
-
- data, err := json.Marshal(webify(mapRemote(x), url.String()))
- if err != nil {
- return InternalError("%v", err)
- }
- raw := json.RawMessage(data)
- results[i] = &raw
- }
-
- return SyncResponse(results, meta)
+ return sendStorePackages(route, meta, found)
}
func shouldSearchStore(r *http.Request) bool {
@@ -419,6 +404,69 @@
return false
}
+func storeUpdates(c *Command, r *http.Request, user *auth.UserState) Response {
+ route := c.d.router.Get(snapCmd.Path)
+ if route == nil {
+ return InternalError("cannot find route for snaps")
+ }
+
+ found, err := allLocalSnapInfos(c.d.overlord.State())
+ if err != nil {
+ return InternalError("cannot list local snaps: %v", err)
+ }
+
+ candidatesInfo := make([]*store.RefreshCandidate, 0, len(found))
+ for _, sn := range found {
+ // snaps in try mode are not considered here
+ if sn.snapst.TryMode() {
+ continue
+ }
+
+ // get confinement preference from the snapstate
+ candidatesInfo = append(candidatesInfo, &store.RefreshCandidate{
+ // the desired channel (not sn.info.Channel!)
+ Channel: sn.snapst.Channel,
+ DevMode: sn.snapst.DevMode(),
+
+ SnapID: sn.info.SnapID,
+ Revision: sn.info.Revision,
+ Epoch: sn.info.Epoch,
+ })
+ }
+
+ var auther store.Authenticator
+ if user != nil {
+ auther = user.Authenticator()
+ }
+ store := getStore(c)
+ updates, err := store.ListRefresh(candidatesInfo, auther)
+ if err != nil {
+ return InternalError("cannot list updates: %v", err)
+ }
+
+ return sendStorePackages(route, nil, updates)
+}
+
+func sendStorePackages(route *mux.Route, meta *Meta, found []*snap.Info) Response {
+ results := make([]*json.RawMessage, 0, len(found))
+ for _, x := range found {
+ url, err := route.URL("name", x.Name())
+ if err != nil {
+ logger.Noticef("Cannot build URL for snap %q revision %s: %v", x.Name(), x.Revision, err)
+ continue
+ }
+
+ data, err := json.Marshal(webify(mapRemote(x), url.String()))
+ if err != nil {
+ return InternalError("%v", err)
+ }
+ raw := json.RawMessage(data)
+ results = append(results, &raw)
+ }
+
+ return SyncResponse(results, meta)
+}
+
// plural!
func getSnapsInfo(c *Command, r *http.Request, user *auth.UserState) Response {
@@ -445,13 +493,13 @@
url, err := route.URL("name", name)
if err != nil {
- logger.Noticef("cannot build URL for snap %q (r%d): %v", name, rev, err)
+ logger.Noticef("cannot build URL for snap %q revision %s: %v", name, rev, err)
continue
}
data, err := json.Marshal(webify(mapLocal(x.info, x.snapst), url.String()))
if err != nil {
- return InternalError("cannot serialize snap %q (r%d): %v", name, rev, err)
+ return InternalError("cannot serialize snap %q revision %s: %v", name, rev, err)
}
raw := json.RawMessage(data)
results[i] = &raw
@@ -485,10 +533,12 @@
type snapInstruction struct {
progress.NullProgress
- Action string `json:"action"`
- Channel string `json:"channel"`
- DevMode bool `json:"devmode"`
- LeaveOld bool `json:"leave-old"`
+ Action string `json:"action"`
+ Channel string `json:"channel"`
+ DevMode bool `json:"devmode"`
+ // dropping support temporarely until flag confusion is sorted,
+ // this isn't supported by client atm anyway
+ LeaveOld bool `json:"temp-dropped-leave-old"`
License *licenseData `json:"license"`
// The fields below should not be unmarshalled into. Do not export them.
@@ -499,6 +549,7 @@
var snapstateInstall = snapstate.Install
var snapstateUpdate = snapstate.Update
var snapstateInstallPath = snapstate.InstallPath
+var snapstateTryPath = snapstate.TryPath
var snapstateGet = snapstate.Get
var errNothingToInstall = errors.New("nothing to install")
@@ -541,12 +592,9 @@
}
func snapInstall(inst *snapInstruction, st *state.State) (string, []*state.TaskSet, error) {
- flags := snappy.DoInstallGC
- if inst.LeaveOld {
- flags = 0
- }
+ flags := snapstate.Flags(0)
if inst.DevMode {
- flags |= snappy.DeveloperMode
+ flags |= snapstate.DevMode
}
tsets, err := withEnsureUbuntuCore(st, inst.snap, inst.userID,
@@ -566,10 +614,7 @@
}
func snapUpdate(inst *snapInstruction, st *state.State) (string, []*state.TaskSet, error) {
- flags := snappy.DoInstallGC
- if inst.LeaveOld {
- flags = 0
- }
+ flags := snapstate.Flags(0)
ts, err := snapstateUpdate(st, inst.snap, inst.Channel, inst.userID, flags)
if err != nil {
@@ -585,11 +630,7 @@
}
func snapRemove(inst *snapInstruction, st *state.State) (string, []*state.TaskSet, error) {
- flags := snappy.DoRemoveGC
- if inst.LeaveOld {
- flags = 0
- }
- ts, err := snapstate.Remove(st, inst.snap, flags)
+ ts, err := snapstate.Remove(st, inst.snap)
if err != nil {
return "", nil, err
}
@@ -657,6 +698,7 @@
}
chg := newChange(state, inst.Action+"-snap", msg, tsets)
+ chg.Set("snap-names", []string{inst.snap})
state.EnsureBefore(0)
return AsyncResponse(nil, &Meta{Change: chg.ID()})
@@ -672,6 +714,37 @@
const maxReadBuflen = 1024 * 1024
+func trySnap(c *Command, r *http.Request, user *auth.UserState, trydir string, flags snapstate.Flags) Response {
+ st := c.d.overlord.State()
+ st.Lock()
+ defer st.Unlock()
+
+ if !filepath.IsAbs(trydir) {
+ return BadRequest("cannot try %q: need an absolute path", trydir)
+ }
+ if !osutil.IsDirectory(trydir) {
+ return BadRequest("cannot try %q: not a snap directory", trydir)
+ }
+
+ info, err := readSnapInfo(trydir)
+ if err != nil {
+ return BadRequest("cannot read snap info for %s: %s", trydir, err)
+ }
+
+ tsets, err := snapstateTryPath(st, info.Name(), trydir, flags)
+ if err != nil {
+ return BadRequest("cannot try %s: %s", trydir, err)
+ }
+
+ msg := fmt.Sprintf(i18n.G("Try %q snap from %q"), info.Name(), trydir)
+ chg := newChange(st, "try-snap", msg, []*state.TaskSet{tsets})
+ chg.Set("api-data", map[string]string{"snap-name": info.Name()})
+
+ st.EnsureBefore(0)
+
+ return AsyncResponse(nil, &Meta{Change: chg.ID()})
+}
+
func sideloadSnap(c *Command, r *http.Request, user *auth.UserState) Response {
route := c.d.router.Get(stateChangeCmd.Path)
if route == nil {
@@ -695,10 +768,17 @@
return BadRequest("cannot read POST form: %v", err)
}
- var flags snappy.InstallFlags
+ var flags snapstate.Flags
if len(form.Value["devmode"]) > 0 && form.Value["devmode"][0] == "true" {
- flags |= snappy.DeveloperMode
+ flags |= snapstate.DevMode
+ }
+
+ if len(form.Value["action"]) > 0 && form.Value["action"][0] == "try" {
+ if len(form.Value["snap-path"]) == 0 {
+ return BadRequest("need 'snap-path' value in form")
+ }
+ return trySnap(c, r, user, form.Value["snap-path"][0], flags)
}
// find the file for the "snap" form field
@@ -774,6 +854,7 @@
chg := newChange(st, "install-snap", msg, tsets)
chg.Set("api-data", map[string]string{"snap-name": snapName})
+ chg.Set("snap-names", []string{snapName})
go func() {
// XXX this needs to be a task in the manager; this is a hack to keep this branch smaller
@@ -904,6 +985,7 @@
}
change := state.NewChange(a.Action+"-snap", summary)
+ change.Set("snap-names", []string{a.Plugs[0].Snap, a.Slots[0].Snap})
change.AddAll(taskset)
state.EnsureBefore(0)
@@ -1072,6 +1154,29 @@
return BadRequest("select should be one of: all,in-progress,ready")
}
+ if wantedName := query.Get("for"); wantedName != "" {
+ outerFilter := filter
+ filter = func(chg *state.Change) bool {
+ if !outerFilter(chg) {
+ return false
+ }
+
+ var snapNames []string
+ if err := chg.Get("snap-names", &snapNames); err != nil {
+ logger.Noticef("cannot get snap-name for change %v", chg.ID())
+ return false
+ }
+
+ for _, snapName := range snapNames {
+ if snapName == wantedName {
+ return true
+ }
+ }
+
+ return false
+ }
+ }
+
state := c.d.overlord.State()
state.Lock()
defer state.Unlock()
diff -Nru snapd-2.0.5/daemon/api_mock_test.go snapd-2.0.8/daemon/api_mock_test.go
--- snapd-2.0.5/daemon/api_mock_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/daemon/api_mock_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,10 +22,10 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
)
func (s *apiSuite) mockSnap(c *C, yamlText string) *snap.Info {
@@ -33,7 +33,7 @@
panic("call s.daemon(c) in your test first")
}
- snapInfo := snaptest.MockSnap(c, yamlText, &snap.SideInfo{Revision: 1})
+ snapInfo := snaptest.MockSnap(c, yamlText, &snap.SideInfo{Revision: snap.R(1)})
snap.AddImplicitSlots(snapInfo)
st := s.d.overlord.State()
diff -Nru snapd-2.0.5/daemon/api_test.go snapd-2.0.8/daemon/api_test.go
--- snapd-2.0.5/daemon/api_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/daemon/api_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -37,18 +37,18 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/overlord/auth"
- "github.com/ubuntu-core/snappy/overlord/ifacestate"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/snappy"
- "github.com/ubuntu-core/snappy/store"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/overlord/auth"
+ "github.com/snapcore/snapd/overlord/ifacestate"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/store"
+ "github.com/snapcore/snapd/testutil"
)
type apiSuite struct {
@@ -58,10 +58,10 @@
searchTerm string
channel string
suggestedCurrency string
- overlord *fakeOverlord
d *Daemon
auther store.Authenticator
restoreBackends func()
+ refreshCandidates []*store.RefreshCandidate
}
var _ = check.Suite(&apiSuite{})
@@ -74,7 +74,7 @@
return nil, s.err
}
-func (s *apiSuite) FindSnaps(searchTerm, channel string, auther store.Authenticator) ([]*snap.Info, error) {
+func (s *apiSuite) Find(searchTerm, channel string, auther store.Authenticator) ([]*snap.Info, error) {
s.searchTerm = searchTerm
s.channel = channel
s.auther = auther
@@ -82,23 +82,29 @@
return s.rsnaps, s.err
}
+func (s *apiSuite) ListRefresh(snaps []*store.RefreshCandidate, auther store.Authenticator) ([]*snap.Info, error) {
+ s.refreshCandidates = snaps
+
+ return s.rsnaps, s.err
+}
+
func (s *apiSuite) SuggestedCurrency() string {
return s.suggestedCurrency
}
+func (s *apiSuite) Download(*snap.Info, progress.Meter, store.Authenticator) (string, error) {
+ panic("Download not expected to be called")
+}
+
func (s *apiSuite) muxVars(*http.Request) map[string]string {
return s.vars
}
func (s *apiSuite) SetUpSuite(c *check.C) {
- newRemoteRepo = func() metarepo {
- return s
- }
muxVars = s.muxVars
}
func (s *apiSuite) TearDownSuite(c *check.C) {
- newRemoteRepo = nil
muxVars = nil
}
@@ -114,11 +120,9 @@
s.channel = ""
s.err = nil
s.vars = nil
- s.overlord = &fakeOverlord{
- configs: map[string]string{},
- }
s.auther = nil
s.d = nil
+ s.refreshCandidates = nil
// Disable real security backends for all API tests
s.restoreBackends = ifacestate.MockSecurityBackends(nil)
}
@@ -139,31 +143,18 @@
d, err := New()
c.Assert(err, check.IsNil)
d.addRoutes()
+
+ d.overlord.SnapManager().ReplaceStore(s)
+
s.d = d
return d
}
-func (s *apiSuite) mkManifest(c *check.C, pkgType snap.Type) {
- // creating the part to get its manifest path is cheating, a little
- sideInfo := snap.SideInfo{
- OfficialName: "foo",
- Developer: "bar",
- Revision: 2147483647,
- EditedDescription: " bla bla bla",
- }
-
- c.Assert(snappy.SaveManifest(&snap.Info{
- Type: pkgType,
- Version: "1",
- SideInfo: sideInfo,
- }), check.IsNil)
-}
-
-func (s *apiSuite) mkInstalled(c *check.C, name, developer, version string, revno int, active bool, extraYaml string) *snap.Info {
+func (s *apiSuite) mkInstalled(c *check.C, name, developer, version string, revno snap.Revision, active bool, extraYaml string) *snap.Info {
return s.mkInstalledInState(c, nil, name, developer, version, revno, active, extraYaml)
}
-func (s *apiSuite) mkInstalledInState(c *check.C, daemon *Daemon, name, developer, version string, revno int, active bool, extraYaml string) *snap.Info {
+func (s *apiSuite) mkInstalledInState(c *check.C, daemon *Daemon, name, developer, version string, revno snap.Revision, active bool, extraYaml string) *snap.Info {
// Collect arguments into a snap.SideInfo structure
sideInfo := &snap.SideInfo{
SnapID: "funky-snap-id",
@@ -188,9 +179,6 @@
c.Assert(os.MkdirAll(guidir, 0755), check.IsNil)
c.Check(ioutil.WriteFile(filepath.Join(guidir, "icon.svg"), []byte("yadda icon"), 0644), check.IsNil)
- err := snappy.SaveManifest(snapInfo)
- c.Assert(err, check.IsNil)
-
if daemon != nil {
st := daemon.overlord.State()
st.Lock()
@@ -204,11 +192,6 @@
snapstate.Set(st, name, &snapst)
}
- if active {
- err := snappy.UpdateCurrentSymlink(snapInfo, nil)
- c.Assert(err, check.IsNil)
- }
-
return snapInfo
}
@@ -218,7 +201,7 @@
type: gadget
gadget: {store: {id: %q}}
`, store)
- snaptest.MockSnap(c, yamlText, &snap.SideInfo{Revision: 1})
+ snaptest.MockSnap(c, yamlText, &snap.SideInfo{Revision: snap.R(1)})
c.Assert(os.Symlink("1", filepath.Join(dirs.SnapSnapsDir, "test", "current")), check.IsNil)
}
@@ -227,9 +210,9 @@
s.vars = map[string]string{"name": "foo"}
// we have v0 [r5] installed
- s.mkInstalledInState(c, d, "foo", "bar", "v0", 5, false, "")
+ s.mkInstalledInState(c, d, "foo", "bar", "v0", snap.R(5), false, "")
// and v1 [r10] is current
- s.mkInstalledInState(c, d, "foo", "bar", "v1", 10, true, "description: description\nsummary: summary")
+ s.mkInstalledInState(c, d, "foo", "bar", "v1", snap.R(10), true, "description: description\nsummary: summary")
req, err := http.NewRequest("GET", "/v2/snaps/foo", nil)
c.Assert(err, check.IsNil)
@@ -254,8 +237,9 @@
Result: map[string]interface{}{
"id": "funky-snap-id",
"name": "foo",
- "revision": 10,
+ "revision": snap.R(10),
"version": "v1",
+ "channel": "stable",
"summary": "summary",
"description": "description",
"developer": "bar",
@@ -263,6 +247,10 @@
"icon": "/v2/icons/foo/icon",
"type": string(snap.TypeApp),
"resource": "/v2/snaps/foo",
+ "private": false,
+ "devmode": false,
+ "confinement": snap.StrictConfinement,
+ "trymode": false,
},
Meta: meta,
}
@@ -290,9 +278,6 @@
}
func (s *apiSuite) TestSnapInfoNotFound(c *check.C) {
- s.vars = map[string]string{"name": "foo"}
- s.err = snappy.ErrPackageNotFound
-
req, err := http.NewRequest("GET", "/v2/snaps/gfoo", nil)
c.Assert(err, check.IsNil)
c.Check(getSnapInfo(snapCmd, req, nil).(*resp).Status, check.Equals, http.StatusNotFound)
@@ -352,13 +337,13 @@
"api",
"maxReadBuflen",
"muxVars",
- "newRemoteRepo",
"errNothingToInstall",
// snapInstruction vars:
"snapInstructionDispTable",
"snapstateInstall",
"snapstateUpdate",
"snapstateInstallPath",
+ "snapstateTryPath",
"snapstateGet",
"readSnapInfo",
}
@@ -397,31 +382,15 @@
rec := httptest.NewRecorder()
c.Check(sysInfoCmd.Path, check.Equals, "/v2/system-info")
- sysInfoCmd.GET(sysInfoCmd, nil, nil).ServeHTTP(rec, nil)
- c.Check(rec.Code, check.Equals, 200)
- c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/json")
-
- expected := map[string]interface{}{
- "series": "16",
- }
- var rsp resp
- c.Assert(json.Unmarshal(rec.Body.Bytes(), &rsp), check.IsNil)
- c.Check(rsp.Status, check.Equals, 200)
- c.Check(rsp.Type, check.Equals, ResponseTypeSync)
- c.Check(rsp.Result, check.DeepEquals, expected)
-}
-
-func (s *apiSuite) TestSysInfoStore(c *check.C) {
- rec := httptest.NewRecorder()
- c.Check(sysInfoCmd.Path, check.Equals, "/v2/system-info")
-
- s.mkGadget(c, "some-store")
+ s.daemon(c).Version = "42b1"
sysInfoCmd.GET(sysInfoCmd, nil, nil).ServeHTTP(rec, nil)
c.Check(rec.Code, check.Equals, 200)
+ c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/json")
expected := map[string]interface{}{
- "series": "16",
+ "series": "16",
+ "version": "42b1",
}
var rsp resp
c.Assert(json.Unmarshal(rec.Body.Bytes(), &rsp), check.IsNil)
@@ -706,7 +675,7 @@
}
for _, snp := range tsnaps {
- s.mkInstalledInState(c, d, snp.name, snp.dev, snp.ver, snp.rev, false, "")
+ s.mkInstalledInState(c, d, snp.name, snp.dev, snp.ver, snap.R(snp.rev), false, "")
}
rsp, ok := getSnapsInfo(snapsCmd, req, nil).(*resp)
@@ -728,8 +697,9 @@
}
c.Check(got["name"], check.Equals, s.name)
c.Check(got["version"], check.Equals, s.ver)
- c.Check(got["revision"], check.Equals, float64(s.rev))
+ c.Check(got["revision"], check.Equals, snap.R(s.rev).String())
c.Check(got["developer"], check.Equals, s.dev)
+ c.Check(got["confinement"], check.Equals, "strict")
}
}
@@ -742,7 +712,7 @@
Developer: "foo",
},
}}
- s.mkInstalledInState(c, d, "local", "foo", "v1", 10, true, "")
+ s.mkInstalledInState(c, d, "local", "foo", "v1", snap.R(10), true, "")
req, err := http.NewRequest("GET", "/v2/snaps?sources=local", nil)
c.Assert(err, check.IsNil)
@@ -780,6 +750,41 @@
c.Check(s.searchTerm, check.Equals, "hi")
c.Check(s.channel, check.Equals, "potato")
+ c.Check(s.refreshCandidates, check.HasLen, 0)
+}
+
+func (s *apiSuite) TestFindRefreshes(c *check.C) {
+ d := s.daemon(c)
+ d.overlord.Loop()
+ defer d.overlord.Stop()
+
+ s.rsnaps = []*snap.Info{{
+ SideInfo: snap.SideInfo{
+ OfficialName: "store",
+ Developer: "foo",
+ },
+ }}
+ s.mockSnap(c, "name: foo\nversion: 1.0")
+
+ req, err := http.NewRequest("GET", "/v2/find?select=refresh", nil)
+ c.Assert(err, check.IsNil)
+
+ rsp := searchStore(findCmd, req, nil).(*resp)
+
+ snaps := snapList(rsp.Result)
+ c.Assert(snaps, check.HasLen, 1)
+ c.Assert(snaps[0]["name"], check.Equals, "store")
+ c.Check(s.refreshCandidates, check.HasLen, 1)
+}
+
+func (s *apiSuite) TestFindRefreshNotQ(c *check.C) {
+ req, err := http.NewRequest("GET", "/v2/find?select=refresh&q=foo", nil)
+ c.Assert(err, check.IsNil)
+
+ rsp := searchStore(findCmd, req, nil).(*resp)
+ c.Check(rsp.Type, check.Equals, ResponseTypeError)
+ c.Check(rsp.Status, check.Equals, http.StatusBadRequest)
+ c.Check(rsp.Result.(*errorResult).Message, check.Matches, "cannot use 'q' with 'select=refresh'")
}
func (s *apiSuite) TestFindPriced(c *check.C) {
@@ -829,7 +834,7 @@
Developer: "foo",
},
}}
- s.mkInstalledInState(c, d, "local", "foo", "v1", 10, true, "")
+ s.mkInstalledInState(c, d, "local", "foo", "v1", snap.R(10), true, "")
req, err := http.NewRequest("GET", "/v2/snaps?sources=store", nil)
c.Assert(err, check.IsNil)
@@ -846,6 +851,47 @@
c.Check(rsp.SuggestedCurrency, check.Equals, "EUR")
}
+func (s *apiSuite) TestSnapsStoreConfinement(c *check.C) {
+ s.rsnaps = []*snap.Info{
+ {
+ // no explicit confinement in this one
+ SideInfo: snap.SideInfo{
+ OfficialName: "foo",
+ },
+ },
+ {
+ Confinement: snap.StrictConfinement,
+ SideInfo: snap.SideInfo{
+ OfficialName: "bar",
+ },
+ },
+ {
+ Confinement: snap.DevmodeConfinement,
+ SideInfo: snap.SideInfo{
+ OfficialName: "baz",
+ },
+ },
+ }
+
+ req, err := http.NewRequest("GET", "/v2/find", nil)
+ c.Assert(err, check.IsNil)
+
+ rsp := searchStore(findCmd, req, nil).(*resp)
+
+ snaps := snapList(rsp.Result)
+ c.Assert(snaps, check.HasLen, 3)
+
+ for i, ss := range [][2]string{
+ {"foo", string(snap.StrictConfinement)},
+ {"bar", string(snap.StrictConfinement)},
+ {"baz", string(snap.DevmodeConfinement)},
+ } {
+ name, mode := ss[0], ss[1]
+ c.Check(snaps[i]["name"], check.Equals, name, check.Commentf(name))
+ c.Check(snaps[i]["confinement"], check.Equals, mode, check.Commentf(name))
+ }
+}
+
func (s *apiSuite) TestSnapsInfoStoreWithAuth(c *check.C) {
state := snapCmd.d.overlord.State()
state.Lock()
@@ -875,7 +921,7 @@
Developer: "foo",
},
}}
- s.mkInstalledInState(c, d, "local", "foo", "v1", 10, true, "")
+ s.mkInstalledInState(c, d, "local", "foo", "v1", snap.R(10), true, "")
req, err := http.NewRequest("GET", "/v2/snaps?sources=local,store", nil)
c.Assert(err, check.IsNil)
@@ -915,7 +961,7 @@
Developer: "foo",
},
}}
- s.mkInstalledInState(c, d, "local", "foo", "v1", 10, true, "")
+ s.mkInstalledInState(c, d, "local", "foo", "v1", snap.R(10), true, "")
req, err := http.NewRequest("GET", "/v2/snaps", nil)
c.Assert(err, check.IsNil)
@@ -934,7 +980,7 @@
Developer: "foo",
},
}}
- s.mkInstalled(c, "local", "foo", "v1", 10, true, "")
+ s.mkInstalled(c, "local", "foo", "v1", snap.R(10), true, "")
req, err := http.NewRequest("GET", "/v2/snaps?sources=unknown", nil)
c.Assert(err, check.IsNil)
@@ -1070,21 +1116,6 @@
}
}
-type fakeOverlord struct {
- configs map[string]string
-}
-
-func (o *fakeOverlord) Configure(s *snappy.Snap, c []byte) ([]byte, error) {
- if len(c) > 0 {
- o.configs[s.Name()] = string(c)
- }
- config, ok := o.configs[s.Name()]
- if !ok {
- return nil, fmt.Errorf("no config for %q", s.Name())
- }
- return []byte(config), nil
-}
-
func (s *apiSuite) TestSideloadSnap(c *check.C) {
// try a multipart/form-data upload
body := "" +
@@ -1115,7 +1146,7 @@
"----hello--\r\n"
head := map[string]string{"Content-Type": "multipart/thing; boundary=--hello--"}
// try a multipart/form-data upload
- chgSummary := s.sideloadCheck(c, body, head, snappy.DeveloperMode, true)
+ chgSummary := s.sideloadCheck(c, body, head, snapstate.DevMode, true)
c.Check(chgSummary, check.Equals, `Install "local" snap from file "x"`)
}
@@ -1145,7 +1176,70 @@
c.Assert(rsp.Result.(*errorResult).Message, check.Matches, `cannot find "snap" file field in provided multipart/form-data payload`)
}
-func (s *apiSuite) sideloadCheck(c *check.C, content string, head map[string]string, expectedFlags snappy.InstallFlags, hasUbuntuCore bool) string {
+func (s *apiSuite) TestTrySnap(c *check.C) {
+ d := newTestDaemon(c)
+ d.overlord.Loop()
+ defer d.overlord.Stop()
+
+ req, err := http.NewRequest("POST", "/v2/snaps", nil)
+ c.Assert(err, check.IsNil)
+
+ // mock a try dir
+ tryDir := c.MkDir()
+ snapYaml := filepath.Join(tryDir, "meta", "snap.yaml")
+ err = os.MkdirAll(filepath.Dir(snapYaml), 0755)
+ c.Assert(err, check.IsNil)
+ err = ioutil.WriteFile(snapYaml, []byte("name: foo\nversion: 1.0\n"), 0644)
+ c.Assert(err, check.IsNil)
+
+ tryWasCalled := true
+ snapstateTryPath = func(s *state.State, name, path string, flags snapstate.Flags) (*state.TaskSet, error) {
+ tryWasCalled = true
+ t := s.NewTask("fake-install-snap", "Doing a fake install")
+ return state.NewTaskSet(t), nil
+ }
+
+ // try the snap
+ rsp := trySnap(snapsCmd, req, nil, tryDir, 0).(*resp)
+ c.Assert(rsp.Type, check.Equals, ResponseTypeAsync)
+ c.Assert(tryWasCalled, check.Equals, true)
+
+ st := d.overlord.State()
+ st.Lock()
+ defer st.Unlock()
+ chg := st.Change(rsp.Change)
+ c.Assert(chg, check.NotNil)
+
+ c.Assert(chg.Tasks(), check.HasLen, 1)
+
+ st.Unlock()
+ <-chg.Ready()
+ st.Lock()
+
+ c.Check(chg.Kind(), check.Equals, "try-snap")
+ c.Check(chg.Summary(), check.Equals, fmt.Sprintf(`Try "%s" snap from %q`, "foo", tryDir))
+
+}
+
+func (s *apiSuite) TestTrySnapRelative(c *check.C) {
+ req, err := http.NewRequest("POST", "/v2/snaps", nil)
+ c.Assert(err, check.IsNil)
+
+ rsp := trySnap(snapsCmd, req, nil, "relative-path", 0).(*resp)
+ c.Assert(rsp.Type, check.Equals, ResponseTypeError)
+ c.Check(rsp.Result.(*errorResult).Message, testutil.Contains, "need an absolute path")
+}
+
+func (s *apiSuite) TestTrySnapNotDir(c *check.C) {
+ req, err := http.NewRequest("POST", "/v2/snaps", nil)
+ c.Assert(err, check.IsNil)
+
+ rsp := trySnap(snapsCmd, req, nil, "/does/not/exist", 0).(*resp)
+ c.Assert(rsp.Type, check.Equals, ResponseTypeError)
+ c.Check(rsp.Result.(*errorResult).Message, testutil.Contains, "not a snap directory")
+}
+
+func (s *apiSuite) sideloadCheck(c *check.C, content string, head map[string]string, expectedFlags snapstate.Flags, hasUbuntuCore bool) string {
d := newTestDaemon(c)
d.overlord.Loop()
defer d.overlord.Stop()
@@ -1163,16 +1257,16 @@
// pretend we do not have a state for ubuntu-core
return state.ErrNoState
}
- snapstateInstall = func(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateInstall = func(s *state.State, name, channel string, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
// NOTE: ubuntu-core is not installed in developer mode
- c.Check(flags, check.Equals, snappy.InstallFlags(0))
+ c.Check(flags, check.Equals, snapstate.Flags(0))
installQueue = append(installQueue, name)
t := s.NewTask("fake-install-snap", "Doing a fake install")
return state.NewTaskSet(t), nil
}
- snapstateInstallPath = func(s *state.State, name, path, channel string, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateInstallPath = func(s *state.State, name, path, channel string, flags snapstate.Flags) (*state.TaskSet, error) {
c.Check(flags, check.Equals, expectedFlags)
bs, err := ioutil.ReadFile(path)
@@ -1223,7 +1317,7 @@
d := s.daemon(c)
// have an active foo in the system
- info := s.mkInstalledInState(c, d, "foo", "bar", "v1", 10, true, "")
+ info := s.mkInstalledInState(c, d, "foo", "bar", "v1", snap.R(10), true, "")
// have an icon for it in the package itself
iconfile := filepath.Join(info.MountDir(), "meta", "gui", "icon.ick")
@@ -1245,7 +1339,7 @@
d := s.daemon(c)
// have an *in*active foo in the system
- info := s.mkInstalledInState(c, d, "foo", "bar", "v1", 10, false, "")
+ info := s.mkInstalledInState(c, d, "foo", "bar", "v1", snap.R(10), false, "")
// have an icon for it in the package itself
iconfile := filepath.Join(info.MountDir(), "meta", "gui", "icon.ick")
@@ -1267,7 +1361,7 @@
d := s.daemon(c)
// have an *in*active foo in the system
- info := s.mkInstalledInState(c, d, "foo", "bar", "v1", 10, true, "")
+ info := s.mkInstalledInState(c, d, "foo", "bar", "v1", snap.R(10), true, "")
// NO ICON!
err := os.RemoveAll(filepath.Join(info.MountDir(), "meta", "gui", "icon.svg"))
@@ -1297,14 +1391,14 @@
}
func (s *apiSuite) TestInstall(c *check.C) {
- calledFlags := snappy.InstallFlags(42)
+ calledFlags := snapstate.Flags(42)
installQueue := []string{}
snapstateGet = func(s *state.State, name string, snapst *snapstate.SnapState) error {
// we have ubuntu-core
return nil
}
- snapstateInstall = func(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateInstall = func(s *state.State, name, channel string, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
calledFlags = flags
installQueue = append(installQueue, name)
@@ -1339,7 +1433,7 @@
st.Lock()
c.Check(chg.Status(), check.Equals, state.DoneStatus)
- c.Check(calledFlags, check.Equals, snappy.DoInstallGC)
+ c.Check(calledFlags, check.Equals, snapstate.Flags(0))
c.Check(err, check.IsNil)
c.Check(installQueue, check.DeepEquals, []string{"some-snap"})
c.Check(chg.Kind(), check.Equals, "install-snap")
@@ -1347,7 +1441,7 @@
}
func (s *apiSuite) TestRefresh(c *check.C) {
- calledFlags := snappy.InstallFlags(42)
+ calledFlags := snapstate.Flags(42)
calledUserID := 0
installQueue := []string{}
@@ -1355,7 +1449,7 @@
// we have ubuntu-core
return nil
}
- snapstateUpdate = func(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateUpdate = func(s *state.State, name, channel string, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
calledFlags = flags
calledUserID = userID
installQueue = append(installQueue, name)
@@ -1377,7 +1471,7 @@
summary, _, err := inst.dispatch()(inst, st)
c.Check(err, check.IsNil)
- c.Check(calledFlags, check.Equals, snappy.DoInstallGC)
+ c.Check(calledFlags, check.Equals, snapstate.Flags(0))
c.Check(calledUserID, check.Equals, 17)
c.Check(err, check.IsNil)
c.Check(installQueue, check.DeepEquals, []string{"some-snap"})
@@ -1391,7 +1485,7 @@
// pretend we do not have a state for ubuntu-core
return state.ErrNoState
}
- snapstateInstall = func(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateInstall = func(s *state.State, name, channel string, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
t1 := s.NewTask("fake-install-snap", name)
t2 := s.NewTask("fake-install-snap", "second task is just here so that we can check that the wait is correctly added to all tasks")
installQueue = append(installQueue, t1, t2)
@@ -1440,7 +1534,7 @@
// pretend we do not have a state for ubuntu-core
return state.ErrNoState
}
- snapstateInstall = func(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateInstall = func(s *state.State, name, channel string, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
t1 := s.NewTask("fake-install-snap", name)
t2 := s.NewTask("fake-install-snap", "second task is just here so that we can check that the wait is correctly added to all tasks")
installQueue = append(installQueue, t1, t2)
@@ -1472,7 +1566,7 @@
return nil
}
- snapstateInstall = func(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateInstall = func(s *state.State, name, channel string, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
t := s.NewTask("fake-install-snap-error", "Install task")
return state.NewTaskSet(t), nil
}
@@ -1506,9 +1600,10 @@
}
func (s *apiSuite) TestInstallLeaveOld(c *check.C) {
- calledFlags := snappy.InstallFlags(42)
+ c.Skip("temporarily dropped half-baked support while sorting out flag mess")
+ calledFlags := snapstate.Flags(42)
- snapstateInstall = func(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateInstall = func(s *state.State, name, channel string, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
calledFlags = flags
t := s.NewTask("fake-install-snap", "Doing a fake install")
@@ -1527,14 +1622,14 @@
_, _, err := inst.dispatch()(inst, st)
c.Assert(err, check.IsNil)
- c.Check(calledFlags, check.Equals, snappy.InstallFlags(0))
+ c.Check(calledFlags, check.Equals, snapstate.Flags(0))
c.Check(err, check.IsNil)
}
func (s *apiSuite) TestInstallDevMode(c *check.C) {
- var calledFlags snappy.InstallFlags
+ var calledFlags snapstate.Flags
- snapstateInstall = func(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+ snapstateInstall = func(s *state.State, name, channel string, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
calledFlags = flags
t := s.NewTask("fake-install-snap", "Doing a fake install")
@@ -1554,8 +1649,8 @@
_, _, err := inst.dispatch()(inst, st)
c.Check(err, check.IsNil)
- // DevMode was converted to the snappy.DeveloperMode flag
- c.Check(calledFlags&snappy.DeveloperMode, check.Equals, snappy.DeveloperMode)
+ // DevMode was converted to the snapstate.DevMode flag
+ c.Check(calledFlags&snapstate.DevMode, check.Equals, snapstate.Flags(snapstate.DevMode))
}
func snapList(rawSnaps interface{}) []map[string]interface{} {
@@ -2307,6 +2402,7 @@
func setupChanges(st *state.State) []string {
chg1 := st.NewChange("install", "install...")
+ chg1.Set("snap-names", []string{"funky-snap-name"})
t1 := st.NewTask("download", "1...")
t2 := st.NewTask("activate", "2...")
chg1.AddAll(state.NewTaskSet(t1, t2))
@@ -2428,6 +2524,35 @@
c.Check(string(res), check.Matches, `.*{"id":"\w+","kind":"remove","summary":"remove..","status":"Error","tasks":\[{"id":"\w+","kind":"unlink","summary":"1...","status":"Error","log":\["2016-04-21T01:02:03Z ERROR rm failed"],"progress":{"done":1,"total":1},"spawn-time":"2016-04-21T01:02:03Z","ready-time":"2016-04-21T01:02:03Z"}.*],"ready":true,"err":"[^"]+".*`)
}
+func (s *apiSuite) TestStateChangesForSnapName(c *check.C) {
+ restore := state.MockTime(time.Date(2016, 04, 21, 1, 2, 3, 0, time.UTC))
+ defer restore()
+
+ // Setup
+ d := newTestDaemon(c)
+ st := d.overlord.State()
+ st.Lock()
+ setupChanges(st)
+ st.Unlock()
+
+ // Execute
+ req, err := http.NewRequest("GET", "/v2/changes?for=funky-snap-name&select=all", nil)
+ c.Assert(err, check.IsNil)
+ rsp := getChanges(stateChangesCmd, req, nil).(*resp)
+
+ // Verify
+ c.Check(rsp.Type, check.Equals, ResponseTypeSync)
+ c.Check(rsp.Status, check.Equals, http.StatusOK)
+ c.Assert(rsp.Result, check.FitsTypeOf, []*changeInfo(nil))
+
+ res := rsp.Result.([]*changeInfo)
+ c.Assert(res, check.HasLen, 1)
+ c.Check(res[0].Kind, check.Equals, `install`)
+
+ _, err = rsp.MarshalJSON()
+ c.Assert(err, check.IsNil)
+}
+
func (s *apiSuite) TestStateChange(c *check.C) {
restore := state.MockTime(time.Date(2016, 04, 21, 1, 2, 3, 0, time.UTC))
defer restore()
diff -Nru snapd-2.0.5/daemon/daemon.go snapd-2.0.8/daemon/daemon.go
--- snapd-2.0.5/daemon/daemon.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/daemon/daemon.go 2016-06-08 05:58:01.000000000 +0000
@@ -30,16 +30,17 @@
"github.com/gorilla/mux"
"gopkg.in/tomb.v2"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/notifications"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/overlord"
- "github.com/ubuntu-core/snappy/overlord/auth"
- "github.com/ubuntu-core/snappy/store"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/notifications"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/overlord"
+ "github.com/snapcore/snapd/overlord/auth"
+ "github.com/snapcore/snapd/store"
)
// A Daemon listens for requests and routes them to the right command
type Daemon struct {
+ Version string
overlord *overlord.Overlord
listener net.Listener
tomb tomb.Tomb
diff -Nru snapd-2.0.5/daemon/daemon_test.go snapd-2.0.8/daemon/daemon_test.go
--- snapd-2.0.5/daemon/daemon_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/daemon/daemon_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
"github.com/gorilla/mux"
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/overlord/auth"
+ "github.com/snapcore/snapd/overlord/auth"
)
// Hook up check.v1 into the "go test" runner
diff -Nru snapd-2.0.5/daemon/response.go snapd-2.0.8/daemon/response.go
--- snapd-2.0.5/daemon/response.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/daemon/response.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,9 +29,9 @@
"github.com/gorilla/websocket"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/notifications"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/notifications"
)
// ResponseType is the response type
diff -Nru snapd-2.0.5/daemon/snap.go snapd-2.0.8/daemon/snap.go
--- snapd-2.0.5/daemon/snap.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/daemon/snap.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,9 +26,9 @@
"path/filepath"
"time"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snap"
)
var errNoSnap = errors.New("no snap installed")
@@ -111,6 +111,13 @@
return about, firstErr
}
+func effectiveConfinement(snapst *snapstate.SnapState) snap.ConfinementType {
+ if snapst.DevMode() {
+ return snap.DevmodeConfinement
+ }
+ return snap.StrictConfinement
+}
+
func mapLocal(localSnap *snap.Info, snapst *snapstate.SnapState) map[string]interface{} {
status := "installed"
if snapst.Active {
@@ -130,6 +137,11 @@
"summary": localSnap.Summary(),
"type": string(localSnap.Type),
"version": localSnap.Version,
+ "channel": localSnap.Channel,
+ "confinement": localSnap.Confinement,
+ "devmode": snapst.DevMode(),
+ "trymode": snapst.TryMode(),
+ "private": localSnap.Private,
}
}
@@ -139,6 +151,11 @@
status = "priced"
}
+ confinement := remoteSnap.Confinement
+ if confinement == "" {
+ confinement = snap.StrictConfinement
+ }
+
result := map[string]interface{}{
"description": remoteSnap.Description(),
"developer": remoteSnap.Developer,
@@ -151,6 +168,9 @@
"summary": remoteSnap.Summary(),
"type": string(remoteSnap.Type),
"version": remoteSnap.Version,
+ "channel": remoteSnap.Channel,
+ "private": remoteSnap.Private,
+ "confinement": confinement,
}
if len(remoteSnap.Prices) > 0 {
diff -Nru snapd-2.0.5/debian/changelog snapd-2.0.8/debian/changelog
--- snapd-2.0.5/debian/changelog 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/changelog 2016-06-08 05:58:01.000000000 +0000
@@ -1,3 +1,99 @@
+snapd (2.0.8) xenial; urgency=medium
+
+ * New upstream release: LP: #1589534
+ - debian: make `snap refresh` times more random (LP: #1537793)
+ - cmd: ExecInCoreSnap looks in "core" snap first, and only in
+ "ubuntu-core" snap if rev>125.
+ - cmd/snap: have 'snap list' display helper message on stderr
+ (LP: #1587445)
+ - snap: make app names more restrictive.
+
+ -- Michael Vogt Wed, 08 Jun 2016 07:56:58 +0200
+
+snapd (2.0.7) xenial; urgency=medium
+
+ * New upstream release: LP: #1589534
+ - debian: do not ship /etc/ld.so.conf.d/snappy.conf (LP: #1589006)
+ - debian: fix snapd.refresh.service install and usage (LP: #1588977)
+ - ovlerlord/state: actually support task setting themself as
+ done/undone
+ - snap: do not use "." import in revision_test.go, as this breaks
+ gccgo-6 (fix build failure on powerpc)
+ - interfaces: add fcitx and mozc input methods to unity7
+ - interfaces: add global gsettings interfaces
+ - interfaces: autoconnect home and doc updates (LP: #1588886)
+ - integration-tests: remove
+ abortSuite.TestAbortWithValidIdInDoingStatus
+ - many: adding backward compatible code to upgrade SnapSetup.Flags
+ - overlord/snapstate: handle sideloading over an old sideloaded snap
+ without panicing
+ - interfaces: add socketcall() to the network/network-bind
+ interfaces (LP: #1588100)
+ - overlord/snapstate,snappy: move over CanRemoveThis moves over the
+ CanRemove check to snapstate itself.overlord/snapstate
+ - snappy: move over CanRemove
+ - overlord/snapstate,snappy: move over CopyData and Remove*Data code
+
+ -- Michael Vogt Mon, 06 Jun 2016 16:35:50 +0200
+
+snapd (2.0.6) xenial; urgency=medium
+
+ * New upstream release: LP: #1588052:
+ - many: repository moved to snapcore/snapd
+ - debian: add transitional pkg for the github location change
+ - snap: ensure `snap try` work with relative paths
+ - debian: drop run/build dependency on lsb-release
+ - asserts/tool: gpg key pair manager
+ - many: add new snap-exec
+ - many: implement `snap refresh --list` and `snap refresh`
+ - snap: add parsing support for hooks.
+ - many: add the cups interface
+ - interfaces: misc policy fixes (LP: #1583794)
+ - many: add `snap try`
+ - interfaces: allow using sysctl and scmp_sys_resolver for parsing
+ kernel logs
+ - debian: make snapd get its environ from /etc/environment
+ - daemon,client,snap: revisions are now strings
+ - interfaces: allow access to new ibus abstract socket path
+ LP: #1580463
+ - integration-tests: add remove tests
+ - asserts: stronger crypto choices and follow better latest designs
+ - snappy,daemon: hollow out more of snappy (either removing or not
+ exporting stuff on its way out), snappy/gadget.go is gone
+ - asserts: rename device-serial to serial
+ - asserts: rename identity to account (and username access)
+ - integration-tests: add changes tests
+ - backend: add tests for environment wrapper generation
+ - interfaces/builtin: add location-control interface
+ - overlord/snapstate: move over check snap logic from snappy
+ - release: use os-release instead of lsb-release for cross-distro
+ use
+ - asserts: allow empty snap-name for snap-declaration
+ - interfaces/builtin,docs,snap: add the pulseaudio interface
+ - many: add support for an environment map inside snap.yaml
+ - overlord/snapstate: increase robustness of doLinkSnap/undoLinkSnap
+ with sanity unit tests
+ - snap: parse epoch property
+ - snappy: do nothing in SetNextBoot when running on classic
+ - snap: validate snap type
+ - integration-tests: extend find command tests
+ - asserts: extend tests to cover mandatory and empty headers
+ - tests: stop the update-pot check in run-checks
+ - snap: parse confinement property.
+ - store: change applyUbuntuStoreHeaders to not take accept, and to
+ take a channel
+ - many: struct-based revisions, new representation
+ - interfaces: remove 'audit deny' rules from network_control.go
+ - interfaces: add com.canonical.UrlLauncher.XdgOpen to unity7
+ interface
+ - interfaces: firewall-control can access xtables lock file
+ - interfaces: allow unity7 AppMenu
+ - interfaces: allow unity7 launcher API
+ - interfaces/builtin: add location-observe interface
+ - snap: fixed snap empty list text LP: #1587445
+
+ -- Michael Vogt Thu, 02 Jun 2016 08:23:50 +0200
+
snapd (2.0.5) xenial; urgency=medium
* New upstream release: LP: #1583085
diff -Nru snapd-2.0.5/debian/control snapd-2.0.8/debian/control
--- snapd-2.0.5/debian/control 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/control 2016-06-08 05:58:01.000000000 +0000
@@ -4,7 +4,7 @@
Maintainer: Ubuntu Developers
Build-Depends: bash-completion,
debhelper (>= 9),
- dh-golang,
+ dh-golang (>=1.7),
dh-systemd,
fakeroot,
gettext,
@@ -23,26 +23,32 @@
golang-yaml.v2-dev,
golang-gopkg-tomb.v2-dev,
golang-websocket-dev,
- lsb-release,
python3,
python3-markdown,
squashfs-tools
Standards-Version: 3.9.7
-Homepage: https://github.com/ubuntu-core/snappy
-Vcs-Browser: https://github.com/ubuntu-core/snappy
-Vcs-Git: https://github.com/ubuntu-core/snappy.git
+Homepage: https://github.com/snapcore/snapd
+Vcs-Browser: https://github.com/snapcore/snapd
+Vcs-Git: https://github.com/snapcore/snapd.git
Package: golang-github-ubuntu-core-snappy-dev
Architecture: all
-Breaks: golang-snappy-dev (<< 1.7.3+20160303ubuntu4)
-Replaces: golang-snappy-dev (<< 1.7.3+20160303ubuntu4)
+Depends: ${misc:Depends}, golang-github-snapcore-snapd-dev
+Section: oldlibs
+Description: transitional dummy package
+ This is a transitional dummy package. It can safely be removed.
+
+Package: golang-github-snapcore-snapd-dev
+Architecture: all
+Breaks: golang-snappy-dev (<< 1.7.3+20160303ubuntu4), golang-github-ubuntu-core-snappy-dev (<< 2.0.6)
+Replaces: golang-snappy-dev (<< 1.7.3+20160303ubuntu4), golang-github-ubuntu-core-snappy-dev (<< 2.0.6)
Depends: ${misc:Depends}
Description: snappy development go packages.
Use these to use the snappy API.
Package: snapd
Architecture: any
-Depends: ${misc:Depends}, ${shlibs:Depends}, adduser, lsb-release,
+Depends: ${misc:Depends}, ${shlibs:Depends}, adduser,
squashfs-tools, ubuntu-core-launcher (>= 1.0.23),
Replaces: ubuntu-snappy (<< 1.9), ubuntu-snappy-cli (<< 1.9)
Breaks: ubuntu-snappy (<< 1.9), ubuntu-snappy-cli (<< 1.9)
diff -Nru snapd-2.0.5/debian/copyright snapd-2.0.8/debian/copyright
--- snapd-2.0.5/debian/copyright 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/copyright 2016-06-08 05:58:01.000000000 +0000
@@ -1,6 +1,6 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: snappy
-Source: https://github.com/ubuntu-core/snappy
+Source: https://github.com/snapcore/snapd
Files: *
Copyright: Copyright (C) 2014,2015 Canonical, Ltd.
diff -Nru snapd-2.0.5/debian/golang-github-snapcore-snapd-dev.install snapd-2.0.8/debian/golang-github-snapcore-snapd-dev.install
--- snapd-2.0.5/debian/golang-github-snapcore-snapd-dev.install 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/debian/golang-github-snapcore-snapd-dev.install 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1 @@
+/usr/share/gocode
diff -Nru snapd-2.0.5/debian/golang-github-ubuntu-core-snappy-dev.install snapd-2.0.8/debian/golang-github-ubuntu-core-snappy-dev.install
--- snapd-2.0.5/debian/golang-github-ubuntu-core-snappy-dev.install 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/golang-github-ubuntu-core-snappy-dev.install 1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-/usr/share/gocode
diff -Nru snapd-2.0.5/debian/rules snapd-2.0.8/debian/rules
--- snapd-2.0.5/debian/rules 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/rules 2016-06-08 05:58:01.000000000 +0000
@@ -3,9 +3,15 @@
#export DH_VERBOSE=1
export DH_OPTIONS
-export DH_GOPKG := github.com/ubuntu-core/snappy
+export DH_GOPKG := github.com/snapcore/snapd
#export DEB_BUILD_OPTIONS=nocheck
export DH_GOLANG_EXCLUDES=integration-tests
+export DH_GOLANG_GO_GENERATE=1
+
+# we need the builddir; is there a simpler way to get it?
+BUILDDIR:=${CURDIR}/obj-$(shell dpkg-architecture -qDEB_TARGET_GNU_TYPE)
+
+export PATH:=${PATH}:${CURDIR}
RELEASE = $(shell lsb_release -c -s)
@@ -21,50 +27,44 @@
dh_systemd_enable \
-pubuntu-core-snapd-units \
snapd.firstboot.service
- # we want the autopilot timer enabled by default
-# dh_systemd_enable \
+ # we want the auto-update timer enabled by default
+ dh_systemd_enable \
-psnapd \
- snappy-autopilot.timer
- # but the autopilot service disabled
-# dh_systemd_enable \
+ snapd.refresh.timer
+ # but the auto-update service disabled
+ dh_systemd_enable \
--no-enable \
-psnapd \
- snappy-autopilot.service
+ snapd.refresh.service
# enable snapd
dh_systemd_enable \
-psnapd \
snapd.socket
+ dh_systemd_enable \
+ -psnapd \
+ snapd.service
override_dh_systemd_start:
# start boot-ok
dh_systemd_start \
-pubuntu-core-snapd-units \
snapd.boot-ok.service
- # we want to start the autopilot timer
-# dh_systemd_start \
+ # we want to start the auto-update timer
+ dh_systemd_start \
-psnapd \
- snappy-autopilot.timer
+ snapd.refresh.timer
# but not start the service
-# dh_systemd_start \
+ dh_systemd_start \
--no-start \
-psnapd \
- snappy-autopilot.service
+ snapd.refresh.service
# start snapd
dh_systemd_start \
-psnapd \
snapd.socket
-
-# we need the builddir; is there a simpler way to get it?
-BUILDDIR:=${CURDIR}/obj-$(shell dpkg-architecture -qDEB_TARGET_GNU_TYPE)
-
-override_dh_auto_build:
- dh_auto_build
- # this will update the i18n stuff using our build-in xgettext-go
- if [ "$(RELEASE)" = "vivid" ]; then\
- GOPATH=${BUILDDIR} ./update-pot;\
- else\
- GOPATH=${BUILDDIR} go generate ./i18n;\
- fi;
+ dh_systemd_start \
+ -psnapd \
+ snapd.service
override_dh_auto_install: snap.8
dh_auto_install -O--buildsystem=golang
diff -Nru snapd-2.0.5/debian/snapd.dirs snapd-2.0.8/debian/snapd.dirs
--- snapd-2.0.5/debian/snapd.dirs 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/snapd.dirs 2016-06-08 05:58:01.000000000 +0000
@@ -2,5 +2,6 @@
var/lib/snapd/snaps
var/lib/snapd/lib/gl
var/lib/snapd/desktop
+var/lib/snapd/environment
usr/lib/snapd
var/snap
diff -Nru snapd-2.0.5/debian/snapd.install snapd-2.0.8/debian/snapd.install
--- snapd-2.0.5/debian/snapd.install 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/snapd.install 2016-06-08 05:58:01.000000000 +0000
@@ -1,5 +1,6 @@
/usr/bin/snap
/usr/bin/snapd usr/lib/snapd
+/usr/bin/snap-exec usr/lib/snapd
data/completion/snap /usr/share/bash-completion/completions/
# i18n stuff
../../share /usr
@@ -7,14 +8,12 @@
etc/profile.d
# etc/X11/Xsession.d will add to XDG_DATA_DIRS so that we have .desktop support
etc/X11
-# etc/ld.so.conf.d contains the SNAP_LIBRARY_PATH directories
-etc/ld.so.conf.d
# systemd stuff
# auto-update
-debian/*.timer /lib/systemd/system/
-debian/snappy-autopilot.service /lib/systemd/system/
+debian/snapd.refresh.timer /lib/systemd/system/
+debian/snapd.refresh.service /lib/systemd/system/
# snapd
debian/*.socket /lib/systemd/system/
debian/snapd.service /lib/systemd/system/
diff -Nru snapd-2.0.5/debian/snapd.maintscript snapd-2.0.8/debian/snapd.maintscript
--- snapd-2.0.5/debian/snapd.maintscript 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/snapd.maintscript 2016-06-08 05:58:01.000000000 +0000
@@ -1,3 +1,5 @@
# we used to ship a custom grub config that is no longer needed
rm_conffile /etc/grub.d/09_snappy 1.7.3ubuntu1
+# keep mount point busy
+rm_conffile /etc/ld.so.conf.d/snappy.conf 2.0.7~
\ No newline at end of file
diff -Nru snapd-2.0.5/debian/snapd.postinst snapd-2.0.8/debian/snapd.postinst
--- snapd-2.0.5/debian/snapd.postinst 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/debian/snapd.postinst 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+#DEBHELPER#
+
+
+case "$1" in
+ configure)
+ # ensure /var/lib/snapd/lib/gl is cleared
+ if dpkg --compare-versions "$2" lt-nl "2.0.7"; then
+ ldconfig
+ fi
+esac
diff -Nru snapd-2.0.5/debian/snapd.refresh.service snapd-2.0.8/debian/snapd.refresh.service
--- snapd-2.0.5/debian/snapd.refresh.service 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/debian/snapd.refresh.service 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,9 @@
+[Unit]
+Description=Automatically refresh installed snaps
+After=network.target
+Documentation=man:snap(1)
+
+# FIXME: add auto-reboot on devices
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/snap refresh
diff -Nru snapd-2.0.5/debian/snapd.refresh.timer snapd-2.0.8/debian/snapd.refresh.timer
--- snapd-2.0.5/debian/snapd.refresh.timer 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/debian/snapd.refresh.timer 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,11 @@
+[Unit]
+Description=Timer to automatically refresh installed snaps
+
+[Timer]
+OnCalendar=23,05,11,17:00
+RandomizedDelaySec=6h
+AccuracySec=10min
+Persistent=true
+
+[Install]
+WantedBy=multi-user.target
diff -Nru snapd-2.0.5/debian/snapd.service snapd-2.0.8/debian/snapd.service
--- snapd-2.0.5/debian/snapd.service 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/snapd.service 2016-06-08 05:58:01.000000000 +0000
@@ -7,6 +7,7 @@
[Service]
ExecStart=/usr/lib/snapd/snapd
+EnvironmentFile=/etc/environment
[Install]
WantedBy=multi-user.target
diff -Nru snapd-2.0.5/debian/snappy-autopilot.service snapd-2.0.8/debian/snappy-autopilot.service
--- snapd-2.0.5/debian/snappy-autopilot.service 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/snappy-autopilot.service 1970-01-01 00:00:00.000000000 +0000
@@ -1,8 +0,0 @@
-[Unit]
-Description=Ubuntu Core Snappy AutoUpdate
-After=network.target
-
-[Service]
-Type=simple
-# FIXME: add auto-reboot on devices
-ExecStart=/usr/bin/snap refresh
diff -Nru snapd-2.0.5/debian/snappy-autopilot.timer snapd-2.0.8/debian/snappy-autopilot.timer
--- snapd-2.0.5/debian/snappy-autopilot.timer 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/snappy-autopilot.timer 1970-01-01 00:00:00.000000000 +0000
@@ -1,12 +0,0 @@
-[Unit]
-Description=Ubuntu Core Snappy AutoUpdate
-
-[Timer]
-OnCalendar=23,05,11,17:00
-RandomizedDelaySec=6h
-AccuracySec=10min
-Persistent=true
-Unit=snappy-autopilot.service
-
-[Install]
-WantedBy=multi-user.target
diff -Nru snapd-2.0.5/debian/tests/integrationtests snapd-2.0.8/debian/tests/integrationtests
--- snapd-2.0.5/debian/tests/integrationtests 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/debian/tests/integrationtests 2016-06-08 05:58:01.000000000 +0000
@@ -4,39 +4,45 @@
set -ex
+# for these tests, run snap and snapd from outside of the core snap
+sudo mkdir -p /etc/systemd/system/snapd.service.d/
+cat <'+message, "utf8"))
+ return
+
+def run():
+ server_address = ('', 8081)
+ httpd = HTTPServer(server_address, testRequestHandler)
+ httpd.serve_forever()
+
+if __name__ == '__main__':
+ sys.exit(run())
diff -Nru snapd-2.0.5/integration-tests/data/snaps/log-observe-consumer/meta/snap.yaml snapd-2.0.8/integration-tests/data/snaps/log-observe-consumer/meta/snap.yaml
--- snapd-2.0.5/integration-tests/data/snaps/log-observe-consumer/meta/snap.yaml 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/data/snaps/log-observe-consumer/meta/snap.yaml 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,10 @@
+name: log-observe-consumer
+version: 1.0
+summary: Basic log-observe consumer snap
+description: A basic snap declaring a plug on log-observe
+
+apps:
+ log-observe-consumer:
+ command: bin/consumer
+ daemon: simple
+ plugs: [network-bind, log-observe]
diff -Nru snapd-2.0.5/integration-tests/data/snaps/network-consumer/bin/consumer snapd-2.0.8/integration-tests/data/snaps/network-consumer/bin/consumer
--- snapd-2.0.5/integration-tests/data/snaps/network-consumer/bin/consumer 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/data/snaps/network-consumer/bin/consumer 2016-06-08 05:58:01.000000000 +0000
@@ -4,7 +4,6 @@
from socket import timeout
import urllib.request
-
if len(sys.argv) > 1:
url = sys.argv[1]
else:
@@ -12,9 +11,12 @@
try:
response = urllib.request.urlopen(url, timeout=3)
- if '' in response.read().decode('utf-8'):
- print('ok')
+ decoded_response = response.read().decode('utf-8')
+ if '' in decoded_response:
+ print(decoded_response.replace('', ''), end="")
except urllib.error.URLError as e:
print("Error, reason: ", e.reason)
+ sys.exit(1)
except timeout:
print("request timeout")
+ sys.exit(1)
diff -Nru snapd-2.0.5/integration-tests/main.go snapd-2.0.8/integration-tests/main.go
--- snapd-2.0.5/integration-tests/main.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/main.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,11 +26,11 @@
"os"
"strconv"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/autopkgtest"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/build"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/config"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/image"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/testutils"
+ "github.com/snapcore/snapd/integration-tests/testutils/autopkgtest"
+ "github.com/snapcore/snapd/integration-tests/testutils/build"
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
+ "github.com/snapcore/snapd/integration-tests/testutils/image"
+ "github.com/snapcore/snapd/integration-tests/testutils/testutils"
)
const (
@@ -77,17 +77,13 @@
"If this flag is used, the image will be updated and then rolled back before running the tests.")
outputDir = flag.String("output-dir", defaultOutputDir, "Directory where test artifacts will be stored.")
shellOnFail = flag.Bool("shell-fail", false, "Run a shell in the testbed if the suite fails.")
- testBuildTags = flag.String("test-build-tags", "", "Build tags to be passed to the go test command")
+ testBuildTags = flag.String("test-build-tags", "allsnaps", "Build tags to be passed to the go test command")
httpProxy = flag.String("http-proxy", "", "HTTP proxy to set in the testbed.")
+ verbose = flag.Bool("v", false, "Show complete test output")
)
flag.Parse()
- build.Assets(&build.Config{
- UseSnappyFromBranch: *useSnappyFromBranch,
- Arch: *arch,
- TestBuildTags: *testBuildTags})
-
// TODO: generate the files out of the source tree. --elopio - 2015-07-15
testutils.PrepareTargetDir(dataOutputDir)
defer os.RemoveAll(dataOutputDir)
@@ -104,9 +100,19 @@
Update: *update,
Rollback: *rollback,
FromBranch: *useSnappyFromBranch,
+ Verbose: *verbose,
}
cfg.Write()
+ err := build.Assets(&build.Config{
+ UseSnappyFromBranch: *useSnappyFromBranch,
+ Arch: *arch,
+ TestBuildTags: *testBuildTags})
+ if err != nil {
+ log.Printf("Assets building failed: %s", err)
+ os.Exit(1)
+ }
+
rootPath := testutils.RootPath()
test := &autopkgtest.AutoPkgTest{
@@ -122,6 +128,7 @@
"TEST_USER_NAME": os.Getenv("TEST_USER_NAME"),
"TEST_USER_PASSWORD": os.Getenv("TEST_USER_PASSWORD"),
},
+ Verbose: *verbose,
}
if !remoteTestbed {
img := &image.Image{
diff -Nru snapd-2.0.5/integration-tests/manual-tests.md snapd-2.0.8/integration-tests/manual-tests.md
--- snapd-2.0.5/integration-tests/manual-tests.md 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/manual-tests.md 2016-06-08 05:58:01.000000000 +0000
@@ -123,3 +123,30 @@
sudo parted -s {dev} unit % print free
* Check that the writable partition was resized to occupy all the empty space.
+
+# Test cups interface by printing something
+
+1. Using ubuntu classic build and install a simple snap with lpr inside.
+
+ name: lpr
+ version: 2.1.3-4
+ summary: submit files for printing
+ description: |
+ lpr submits files for printing. Files named on the command line are sent to
+ the named printer or the default destination if no destination is specified.
+ If no files are listed on the command-line, lpr reads the print file from
+ the standard input.
+ apps:
+ lpr:
+ command: lpr
+ plugs: [cups]
+ parts:
+ lpr:
+ plugin: nil
+ stage-packages: [cups-bsd]
+2. Ensure that the 'cups' interface is connected to lpr
+3. Use /snap/bin/lpr to print a short text file (e.g. the snapcraft file)
+4. Ensure that it was added to the queue of the default CUPS printer. This can
+ be checked in the ubuntu-control-center under the printers applet. Right
+ click on the default printer and look at the queue. Ensure it contains the
+ new item.
diff -Nru snapd-2.0.5/integration-tests/README.md snapd-2.0.8/integration-tests/README.md
--- snapd-2.0.5/integration-tests/README.md 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/README.md 2016-06-08 05:58:01.000000000 +0000
@@ -155,6 +155,40 @@
s.SnappySuite.TearDownTest(c)
}
+### Classic-only and all-snaps-only tests
+
+There are some integration tests which only work in classic ubuntu systems, and
+some which only work in all-snaps systems.
+
+These tests are guarded by a build tag. If you develop a test that will work
+only in one type of system remember to add corresponding tag to the top of the
+file.
+
+For tests that will run only in a classic system, use:
+
+```
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration,!allsnaps
+...
+```
+
+For tests that will run only in an all-snap system, use
+```
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration,!classic
+...
+```
+
+The autopkgtest runner uses a classic testbed so it will exclude the
+all-snaps-only tests by passing the classic tag.
+
+The main.go runner executes by default in an all-snaps system so it will
+exclude the classic-only tests by passing the all-snaps tag. If you are
+using this runner to execute the tests in a classic system you can run the
+right set of tests by passing the flag:
+
+ go run integration-tests/main.go -test-build-tags=classic
+
### Tests with reboots
`adt-run` supports reboots during tests. A test can request a reboot specifying
@@ -202,7 +236,11 @@
This allows to exclude the tests that require a reboot by passing `excludereboots`
to the `test-build-tags` flag:
- go run integration-tests/main.go -test-build-tags=excludereboots
+ go run integration-tests/main.go -test-build-tags=excludereboots,classic
+
+or:
+
+ go run integration-tests/main.go -test-build-tags=excludereboots,allsnaps
### Update-rollback stress test
@@ -230,21 +268,6 @@
go run integration-tests/main.go -test-build-tags=lowperformance
-### Classic-only tests
-
-There are certain integration tests which at the moment only work in classic ubuntu systems, for
-instance the unity suite, which checks features that currently are only available in desktop systems.
-
-These tests are guarded by the `classiconly` build tag, the autopkgtest runner is configured to
-include it when building the tests' binary. If you develop a test of this type remember to add it at
-the top of the file:
-
-```
-// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration,classiconly
-...
-```
-
### Store tests
We have marked some of the tests that exercise the different endpoints of the store so that they can be
diff -Nru snapd-2.0.5/integration-tests/tests/apparmor_test.go snapd-2.0.8/integration-tests/tests/apparmor_test.go
--- snapd-2.0.5/integration-tests/tests/apparmor_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/apparmor_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,11 +23,11 @@
import (
"os"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/build"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/integration-tests/testutils/build"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/testutil"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/apt_test.go snapd-2.0.8/integration-tests/tests/apt_test.go
--- snapd-2.0.5/integration-tests/tests/apt_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/apt_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -1,8 +1,8 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration
+// +build !excludeintegration,!classic
/*
- * Copyright (C) 2015 Canonical Ltd
+ * Copyright (C) 2015, 2016 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -21,8 +21,8 @@
package tests
import (
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/auth_test.go snapd-2.0.8/integration-tests/tests/auth_test.go
--- snapd-2.0.5/integration-tests/tests/auth_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/auth_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,9 +26,9 @@
"os/user"
"path/filepath"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/testutil"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/base_test.go snapd-2.0.8/integration-tests/tests/base_test.go
--- snapd-2.0.5/integration-tests/tests/base_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/base_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -31,12 +31,13 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/config"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/partition"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/report"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/runner"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/wait"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
+ "github.com/snapcore/snapd/integration-tests/testutils/partition"
+ "github.com/snapcore/snapd/integration-tests/testutils/report"
+ "github.com/snapcore/snapd/integration-tests/testutils/runner"
+ "github.com/snapcore/snapd/integration-tests/testutils/wait"
+ "github.com/snapcore/snapd/osutil"
)
const (
@@ -53,8 +54,14 @@
wait.ForFunction(c, "regular", partition.Mode)
if _, err := os.Stat(config.DefaultFileName); err == nil {
- cli.ExecCommand(c, "sudo", "systemctl", "stop", "snappy-autopilot.timer")
- cli.ExecCommand(c, "sudo", "systemctl", "disable", "snappy-autopilot.timer")
+ timerName := "snapd.refresh.timer"
+ // FIXME: compat with old os images, kill once we have released
+ // a stable OS snap with snapd 2.0.7
+ if osutil.FileExists("/lib/systemd/system/snappy-autopilot.service") {
+ timerName = "snappy-autopilot.timer"
+ }
+ cli.ExecCommand(c, "sudo", "systemctl", "stop", timerName)
+ cli.ExecCommand(c, "sudo", "systemctl", "disable", timerName)
cfg, err := config.ReadConfig(config.DefaultFileName)
c.Assert(err, check.IsNil, check.Commentf("Error reading config: %v", err))
diff -Nru snapd-2.0.5/integration-tests/tests/grub_test.go snapd-2.0.8/integration-tests/tests/grub_test.go
--- snapd-2.0.5/integration-tests/tests/grub_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/grub_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -1,5 +1,5 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration
+// +build !excludeintegration,!classic
/*
* Copyright (C) 2016 Canonical Ltd
@@ -23,9 +23,9 @@
import (
"fmt"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/partition"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/partition"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/home_interface_test.go snapd-2.0.8/integration-tests/tests/home_interface_test.go
--- snapd-2.0.5/integration-tests/tests/home_interface_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/home_interface_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,8 +25,8 @@
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
"gopkg.in/check.v1"
)
@@ -35,7 +35,8 @@
interfaceSuite: interfaceSuite{
sampleSnaps: []string{data.HomeConsumerSnapName},
slot: "home",
- plug: "home-consumer"}})
+ plug: "home-consumer",
+ autoconnect: true}})
type homeInterfaceSuite struct {
interfaceSuite
diff -Nru snapd-2.0.5/integration-tests/tests/installApp_test.go snapd-2.0.8/integration-tests/tests/installApp_test.go
--- snapd-2.0.5/integration-tests/tests/installApp_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/installApp_test.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,90 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration
-
-/*
- * Copyright (C) 2015, 2016 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package tests
-
-import (
- "os"
-
- "github.com/ubuntu-core/snappy/integration-tests/testutils/build"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
- "github.com/ubuntu-core/snappy/testutil"
-
- "gopkg.in/check.v1"
-)
-
-var _ = check.Suite(&installAppSuite{})
-
-type installAppSuite struct {
- common.SnappySuite
-}
-
-func (s *installAppSuite) TestInstallAppMustPrintPackageInformation(c *check.C) {
- snapPath, err := build.LocalSnap(c, data.BasicSnapName)
- defer os.Remove(snapPath)
- c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
- installOutput := common.InstallSnap(c, snapPath)
- defer common.RemoveSnap(c, data.BasicSnapName)
-
- expected := "(?ms)" +
- "Name +Version +Rev +Developer\n" +
- ".*" +
- "^basic +.* *\n" +
- ".*"
-
- c.Assert(installOutput, check.Matches, expected)
-}
-
-func (s *installAppSuite) TestCallSuccessfulBinaryFromInstalledSnap(c *check.C) {
- snapPath, err := build.LocalSnap(c, data.BasicBinariesSnapName)
- defer os.Remove(snapPath)
- c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
- common.InstallSnap(c, snapPath)
- defer common.RemoveSnap(c, data.BasicBinariesSnapName)
-
- // Exec command does not fail.
- cli.ExecCommand(c, "basic-binaries.success")
-}
-
-func (s *installAppSuite) TestCallFailBinaryFromInstalledSnap(c *check.C) {
- c.Skip("port to snapd")
-
- snapPath, err := build.LocalSnap(c, data.BasicBinariesSnapName)
- defer os.Remove(snapPath)
- c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
- common.InstallSnap(c, snapPath)
- defer common.RemoveSnap(c, data.BasicBinariesSnapName)
-
- _, err = cli.ExecCommandErr("basic-binaries.fail")
- c.Assert(err, check.NotNil, check.Commentf("The binary did not fail"))
-}
-
-func (s *installAppSuite) TestInstallUnexistingAppMustPrintError(c *check.C) {
- output, err := cli.ExecCommandErr("sudo", "snap", "install", "unexisting.canonical")
-
- c.Check(err, check.NotNil,
- check.Commentf("Trying to install an unexisting snap did not exit with an error"))
- c.Assert(string(output), testutil.Contains,
- "error: cannot perform the following tasks:\n"+
- "- Download snap \"unexisting.canonical\" from channel \"stable\" (snap not found)\n",
- check.Commentf("Wrong error message"))
-}
diff -Nru snapd-2.0.5/integration-tests/tests/installDesktopApp_test.go snapd-2.0.8/integration-tests/tests/installDesktopApp_test.go
--- snapd-2.0.5/integration-tests/tests/installDesktopApp_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/installDesktopApp_test.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,58 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration
-
-/*
- * Copyright (C) 2015, 2016 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package tests
-
-import (
- "io/ioutil"
- "os"
- "path/filepath"
-
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/testutil"
-
- "github.com/ubuntu-core/snappy/integration-tests/testutils/build"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
-
- "gopkg.in/check.v1"
-)
-
-var _ = check.Suite(&installDesktopAppSuite{})
-
-type installDesktopAppSuite struct {
- common.SnappySuite
-}
-
-func (s *installDesktopAppSuite) TestInstallsDesktopFile(c *check.C) {
- snapPath, err := build.LocalSnap(c, data.BasicDesktopSnapName)
- defer os.Remove(snapPath)
- c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
- common.InstallSnap(c, snapPath)
- defer common.RemoveSnap(c, data.BasicDesktopSnapName)
-
- content, err := ioutil.ReadFile(filepath.Join(dirs.SnapDesktopFilesDir, "basic-desktop_echo.desktop"))
- c.Assert(err, check.IsNil)
- c.Assert(string(content), testutil.Contains, `[Desktop Entry]
-Name=Echo
-Comment=It echos stuff
-Exec=/snap/bin/basic-desktop.echo
-`)
-}
diff -Nru snapd-2.0.5/integration-tests/tests/interfaces_test.go snapd-2.0.8/integration-tests/tests/interfaces_test.go
--- snapd-2.0.5/integration-tests/tests/interfaces_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/interfaces_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,9 +24,9 @@
"fmt"
"os"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/build"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/build"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/list_test.go snapd-2.0.8/integration-tests/tests/list_test.go
--- snapd-2.0.5/integration-tests/tests/list_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/list_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -1,8 +1,8 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration
+// +build !excludeintegration,!classic
/*
- * Copyright (C) 2015 Canonical Ltd
+ * Copyright (C) 2015, 2016 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -22,10 +22,14 @@
import (
"fmt"
+ "io/ioutil"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/partition"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
+ "github.com/snapcore/snapd/integration-tests/testutils/partition"
+ "github.com/snapcore/snapd/integration-tests/testutils/refresh"
+ "github.com/snapcore/snapd/integration-tests/testutils/store"
"gopkg.in/check.v1"
)
@@ -42,9 +46,9 @@
listOutput := cli.ExecCommand(c, "snap", "list")
expected := "(?ms)" +
- "Name +Version +Rev +Developer *\n" +
+ "Name +Version +Rev +Developer +Notes *\n" +
".*" +
- fmt.Sprintf("^%s +.* +%s + [0-9]+ +(canonical|sideload) *\n", partition.OSSnapName(c), verRegexp) +
+ fmt.Sprintf("^%s +.* +%s +[0-9]+ +canonical +- *\n", partition.OSSnapName(c), verRegexp) +
".*"
c.Assert(listOutput, check.Matches, expected)
}
@@ -57,9 +61,44 @@
listOutput := cli.ExecCommand(c, "snap", "list")
expected := "(?ms)" +
- "Name +Version +Rev +Developer *\n" +
+ "Name +Version +Rev +Developer +Notes *\n" +
".*" +
- "^hello-world +(\\d+)(\\.\\d+)* +[0-9]+ +.* *\n" +
+ "^hello-world +(\\d+)(\\.\\d+)* +[0-9]+ +\\S+ +-\n" +
+ ".*"
+
+ c.Assert(listOutput, check.Matches, expected)
+}
+
+func (s *listSuite) TestRefreshListSimple(c *check.C) {
+ snap := "hello-world"
+
+ common.InstallSnap(c, snap)
+ s.AddCleanup(func() {
+ common.RemoveSnap(c, snap)
+ })
+
+ // fake refresh
+ blobDir, err := ioutil.TempDir("", "snap-fake-store-blobs-")
+ fakeStore := store.NewStore(blobDir)
+ err = fakeStore.Start()
+ c.Assert(err, check.IsNil)
+ defer fakeStore.Stop()
+
+ env := fmt.Sprintf(`SNAPPY_FORCE_CPI_URL=%s`, fakeStore.URL())
+ cfg, _ := config.ReadConfig(config.DefaultFileName)
+
+ tearDownSnapd(c)
+ defer setUpSnapd(c, cfg.FromBranch, "")
+ setUpSnapd(c, cfg.FromBranch, env)
+ defer tearDownSnapd(c)
+
+ refresh.MakeFakeRefreshForSnap(c, snap, blobDir, refresh.NoOp)
+
+ listOutput := cli.ExecCommand(c, "snap", "refresh", "--list")
+ expected := "(?ms)" +
+ "Name +Version +Developer +Notes +Summary *\n" +
+ ".*" +
+ "^hello-world +(\\d+)(\\.\\d+)\\+fake1 +canonical +- .*\n" +
".*"
c.Assert(listOutput, check.Matches, expected)
diff -Nru snapd-2.0.5/integration-tests/tests/login_test.go snapd-2.0.8/integration-tests/tests/login_test.go
--- snapd-2.0.5/integration-tests/tests/login_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/login_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -1,5 +1,5 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration
+// +build !excludeintegration,!classic
/*
* Copyright (C) 2015, 2016 Canonical Ltd
@@ -34,9 +34,9 @@
"gopkg.in/check.v1"
"github.com/kr/pty"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/wait"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/wait"
)
const (
diff -Nru snapd-2.0.5/integration-tests/tests/log_observe_interface_test.go snapd-2.0.8/integration-tests/tests/log_observe_interface_test.go
--- snapd-2.0.5/integration-tests/tests/log_observe_interface_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/log_observe_interface_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,51 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
+)
+
+var _ = check.Suite(&logObserveInterfaceSuite{
+ interfaceSuite: interfaceSuite{
+ sampleSnaps: []string{data.LogObserveConsumerSnapName, data.NetworkConsumerSnapName},
+ slot: "log-observe",
+ plug: "log-observe-consumer"}})
+
+type logObserveInterfaceSuite struct {
+ interfaceSuite
+}
+
+func (s *logObserveInterfaceSuite) TestConnectedPlugAllowsLogObserve(c *check.C) {
+ cli.ExecCommand(c, "sudo", "snap", "connect",
+ s.plug+":"+s.slot, "ubuntu-core:"+s.slot)
+
+ output := cli.ExecCommand(c, "network-consumer", "http://127.0.0.1:8081")
+ c.Assert(output, check.Equals, "ok\n")
+}
+
+func (s *logObserveInterfaceSuite) TestDisconnectedPlugDisablesLogObserve(c *check.C) {
+ output := cli.ExecCommand(c, "network-consumer", "http://127.0.0.1:8081")
+ c.Assert(output, check.Equals, "error accessing log\n")
+}
diff -Nru snapd-2.0.5/integration-tests/tests/network_bind_interface_test.go snapd-2.0.8/integration-tests/tests/network_bind_interface_test.go
--- snapd-2.0.5/integration-tests/tests/network_bind_interface_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/network_bind_interface_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,8 +23,8 @@
import (
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
)
const providerURL = "http://127.0.0.1:8081"
@@ -50,6 +50,6 @@
output = cli.ExecCommand(c, "snap", "interfaces")
c.Assert(output, check.Matches, disconnectedPattern(s.slot, s.plug))
- output = cli.ExecCommand(c, "network-consumer", providerURL)
- c.Assert(output, check.Equals, "request timeout\n")
+ output, err := cli.ExecCommandErr("network-consumer", providerURL)
+ c.Assert(err, check.NotNil)
}
diff -Nru snapd-2.0.5/integration-tests/tests/network_interface_test.go snapd-2.0.8/integration-tests/tests/network_interface_test.go
--- snapd-2.0.5/integration-tests/tests/network_interface_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/network_interface_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -21,8 +21,8 @@
package tests
import (
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
"gopkg.in/check.v1"
)
@@ -50,6 +50,6 @@
output = cli.ExecCommand(c, "snap", "interfaces")
c.Assert(output, check.Matches, disconnectedPattern(s.slot, s.plug))
- output = cli.ExecCommand(c, "network-consumer", providerURL)
- c.Assert(output, check.Equals, "Error, reason: [Errno 13] Permission denied\n")
+ output, err := cli.ExecCommandErr("network-consumer", providerURL)
+ c.Check(err, check.NotNil)
}
diff -Nru snapd-2.0.5/integration-tests/tests/service_test.go snapd-2.0.8/integration-tests/tests/service_test.go
--- snapd-2.0.5/integration-tests/tests/service_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/service_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,12 +25,12 @@
"os"
"regexp"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/build"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/wait"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/integration-tests/testutils/build"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/integration-tests/testutils/wait"
+ "github.com/snapcore/snapd/testutil"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/snap_abort_test.go snapd-2.0.8/integration-tests/tests/snap_abort_test.go
--- snapd-2.0.5/integration-tests/tests/snap_abort_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_abort_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,145 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "fmt"
+ "path/filepath"
+ "regexp"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+
+ "gopkg.in/check.v1"
+)
+
+const nothingPendingErrorTpl = "error: cannot abort change %s with nothing pending\n"
+
+var _ = check.Suite(&abortSuite{})
+
+type abortSuite struct {
+ common.SnappySuite
+}
+
+// SNAP_ABORT_001: --help - print detailed help text for the abort command
+func (s *abortSuite) TestAbortShowHelp(c *check.C) {
+ expected := "(?ms)" +
+ "^Usage:\n" +
+ ` snap \[OPTIONS\] abort.*\n` +
+ "\n^The abort command .*\n" +
+ "^Help Options:\n" +
+ "^ -h, --help +Show this help message\n" +
+ ".*"
+
+ actual := cli.ExecCommand(c, "snap", "abort", "--help")
+
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_ABORT_002: with invalid id
+func (s *abortSuite) TestAbortWithInvalidId(c *check.C) {
+ id := "10000000"
+
+ expected := fmt.Sprintf(`error: cannot find change with id "%s"\n`, id)
+ actual, err := cli.ExecCommandErr("sudo", "snap", "abort", id)
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_ABORT_004: with valid id - error
+func (s *abortSuite) TestAbortWithValidIdInErrorStatus(c *check.C) {
+ snapName := "hello-world"
+
+ provokeTaskError(c, snapName)
+
+ id := getErrorID(snapName)
+ c.Assert(id, check.Not(check.Equals), "")
+
+ expected := fmt.Sprintf(nothingPendingErrorTpl, id)
+ actual, err := cli.ExecCommandErr("sudo", "snap", "abort", id)
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_ABORT_006: with valid id - done
+func (s *abortSuite) TestAbortWithValidIdInDoneStatus(c *check.C) {
+ snapName := "hello-world"
+ common.InstallSnap(c, snapName)
+ defer common.RemoveSnap(c, snapName)
+
+ id := getDoneInstallID(snapName)
+ c.Assert(id, check.Not(check.Equals), "")
+
+ expected := fmt.Sprintf(nothingPendingErrorTpl, id)
+ actual, err := cli.ExecCommandErr("sudo", "snap", "abort", id)
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
+
+func provokeTaskError(c *check.C, snapName string) {
+ // make snap uninstallable
+ subdirPath := filepath.Join("/snap", snapName, "current", "foo")
+ _, err := cli.ExecCommandErr("sudo", "mkdir", "-p", subdirPath)
+ c.Assert(err, check.IsNil)
+ defer cli.ExecCommand(c, "sudo", "rm", "-rf", filepath.Dir(subdirPath))
+
+ // try to install snap and see it fail
+ _, err = cli.ExecCommandErr("sudo", "snap", "install", snapName)
+ c.Assert(err, check.NotNil)
+}
+
+func getErrorID(snapName string) string {
+ pattern := fmt.Sprintf(` +Error.*Install "%s" snap`, snapName)
+ return getID(pattern)
+}
+
+func getDoneInstallID(snapName string) string {
+ pattern := fmt.Sprintf(` +Done +.*Install "%s" snap`, snapName)
+ return getID(pattern)
+}
+
+func getDoingRemoveID(snapName string) string {
+ pattern := fmt.Sprintf(` +Doing +.*Remove "%s" snap`, snapName)
+ return getID(pattern)
+}
+
+func getAbortedRemoveID(snapName string) string {
+ pattern := fmt.Sprintf(` +Abort +.*Remove "%s" snap`, snapName)
+ return getID(pattern)
+}
+
+func getID(pattern string) string {
+ output, err := cli.ExecCommandErr("snap", "changes")
+ if err != nil && output == "error: no changes found\n" {
+ return ""
+ }
+
+ completePattern := fmt.Sprintf(`(?msU).*\n(\d+)%s\n$`, pattern)
+ result := regexp.MustCompile(completePattern).FindStringSubmatch(output)
+
+ if result == nil || len(result) < 2 {
+ return ""
+ }
+ return result[1]
+}
diff -Nru snapd-2.0.5/integration-tests/tests/snap_ack_test.go snapd-2.0.8/integration-tests/tests/snap_ack_test.go
--- snapd-2.0.5/integration-tests/tests/snap_ack_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_ack_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,9 +25,9 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
)
// for cleanup
diff -Nru snapd-2.0.5/integration-tests/tests/snap_changes_test.go snapd-2.0.8/integration-tests/tests/snap_changes_test.go
--- snapd-2.0.5/integration-tests/tests/snap_changes_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_changes_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,63 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "fmt"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+
+ "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&changesSuite{})
+
+type changesSuite struct {
+ common.SnappySuite
+}
+
+// SNAP_CHANGES_001: --help prints the detailed help test for the command
+func (s *changesSuite) TestChangesShowsHelp(c *check.C) {
+ expected := "(?ms)" +
+ "^Usage:\n" +
+ ` snap \[OPTIONS\] changes.*\n` +
+ "\n^The changes command .*\n" +
+ "^Help Options:\n" +
+ "^ -h, --help +Show this help message\n" +
+ ".*"
+
+ actual := cli.ExecCommand(c, "snap", "changes", "--help")
+
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_CHANGES_004: with invalid id
+func (s *changesSuite) TestChangesWithInvalidIdShowsError(c *check.C) {
+ invalidID := "10000000"
+
+ expected := fmt.Sprintf(`error: cannot find change with id "%s"\n`, invalidID)
+
+ actual, err := cli.ExecCommandErr("snap", "change", invalidID)
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
diff -Nru snapd-2.0.5/integration-tests/tests/snap_example_test.go snapd-2.0.8/integration-tests/tests/snap_example_test.go
--- snapd-2.0.5/integration-tests/tests/snap_example_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_example_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,10 +24,10 @@
"io/ioutil"
"net/http"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/wait"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/wait"
+ "github.com/snapcore/snapd/testutil"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/snap_find_test.go snapd-2.0.8/integration-tests/tests/snap_find_test.go
--- snapd-2.0.5/integration-tests/tests/snap_find_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_find_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -21,8 +21,10 @@
package tests
import (
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
+ "runtime"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
"gopkg.in/check.v1"
)
@@ -36,7 +38,7 @@
func (s *searchSuite) TestSearchMustPrintMatch(c *check.C) {
// XXX: Summary is empty atm, waiting for store support
expected := "(?ms)" +
- "Name +Version +Summary *\n" +
+ "Name +Version +Developer +Notes +Summary *\n" +
".*" +
"^hello-world +.* *\n" +
".*"
@@ -47,3 +49,63 @@
c.Check(searchOutput, check.Matches, expected)
}
}
+
+// SNAP_FIND_001: list all packages available on the store
+func (s *searchSuite) TestFindMustPrintCompleteList(c *check.C) {
+ if runtime.GOARCH != "amd64" {
+ c.Skip("all find results are only available on amd64")
+ }
+
+ fullListPattern := "(?ms)" +
+ "Name +Version +Developer +Notes +Summary *\n" +
+ ".*" +
+ "^canonical-pc +.* *\n" +
+ ".*" +
+ "^canonical-pc-linux +.* *\n" +
+ ".*" +
+ "^go-example-webserver +.* *\n" +
+ ".*" +
+ "^hello-world +.* *\n" +
+ ".*" +
+ "^ubuntu-clock-app +.* *\n" +
+ ".*" +
+ "^ubuntu-core +.* *\n" +
+ ".*"
+
+ searchOutput := cli.ExecCommand(c, "snap", "find")
+
+ c.Assert(searchOutput, check.Matches, fullListPattern)
+}
+
+// SNAP_FIND_002: find packages on store with different name formats
+func (s *searchSuite) TestFindWorksWithDifferentFormats(c *check.C) {
+ if runtime.GOARCH != "amd64" {
+ c.Skip("all find results are only available on amd64")
+ }
+
+ for _, snapName := range []string{"http", "ubuntu-clock-app", "go-example-webserver"} {
+ expected := "(?ms)" +
+ "Name +Version +Developer +Notes +Summary *\n" +
+ ".*" +
+ "^" + snapName + " +.* *\n" +
+ ".*"
+ searchOutput := cli.ExecCommand(c, "snap", "find", snapName)
+
+ c.Check(searchOutput, check.Matches, expected)
+ }
+}
+
+// SNAP_FIND_003: --help prints the detailed help test for the command
+func (s *searchSuite) TestFindShowsHelp(c *check.C) {
+ expected := "(?ms)" +
+ "^Usage:\n" +
+ ` snap \[OPTIONS\] find.*\n` +
+ "\n^The find command .*\n" +
+ "^Help Options:\n" +
+ "^ -h, --help +Show this help message\n" +
+ ".*"
+
+ actual := cli.ExecCommand(c, "snap", "find", "--help")
+
+ c.Assert(actual, check.Matches, expected)
+}
diff -Nru snapd-2.0.5/integration-tests/tests/snap_install_test.go snapd-2.0.8/integration-tests/tests/snap_install_test.go
--- snapd-2.0.5/integration-tests/tests/snap_install_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_install_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,192 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration
+
+/*
+ * Copyright (C) 2015, 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/integration-tests/testutils/build"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/testutil"
+
+ "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&installSuite{})
+
+type installSuite struct {
+ common.SnappySuite
+}
+
+func (s *installSuite) TestInstallAppMustPrintPackageInformation(c *check.C) {
+ snapPath, err := build.LocalSnap(c, data.BasicSnapName)
+ defer os.Remove(snapPath)
+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
+ installOutput := common.InstallSnap(c, snapPath)
+ defer common.RemoveSnap(c, data.BasicSnapName)
+
+ expected := "(?ms)" +
+ "Name +Version +Rev +Developer +Notes\n" +
+ ".*" +
+ "^basic +.* *\n" +
+ ".*"
+
+ c.Assert(installOutput, check.Matches, expected)
+}
+
+func (s *installSuite) TestCallSuccessfulBinaryFromInstalledSnap(c *check.C) {
+ snapPath, err := build.LocalSnap(c, data.BasicBinariesSnapName)
+ defer os.Remove(snapPath)
+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
+ common.InstallSnap(c, snapPath)
+ defer common.RemoveSnap(c, data.BasicBinariesSnapName)
+
+ // Exec command does not fail.
+ cli.ExecCommand(c, "basic-binaries.success")
+}
+
+func (s *installSuite) TestCallFailBinaryFromInstalledSnap(c *check.C) {
+ c.Skip("port to snapd")
+
+ snapPath, err := build.LocalSnap(c, data.BasicBinariesSnapName)
+ defer os.Remove(snapPath)
+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
+ common.InstallSnap(c, snapPath)
+ defer common.RemoveSnap(c, data.BasicBinariesSnapName)
+
+ _, err = cli.ExecCommandErr("basic-binaries.fail")
+ c.Assert(err, check.NotNil, check.Commentf("The binary did not fail"))
+}
+
+func (s *installSuite) TestInstallUnexistingAppMustPrintError(c *check.C) {
+ output, err := cli.ExecCommandErr("sudo", "snap", "install", "unexisting.canonical")
+
+ c.Check(err, check.NotNil,
+ check.Commentf("Trying to install an unexisting snap did not exit with an error"))
+ c.Assert(string(output), testutil.Contains,
+ "error: cannot perform the following tasks:\n"+
+ "- Download snap \"unexisting.canonical\" from channel \"stable\" (snap not found)\n",
+ check.Commentf("Wrong error message"))
+}
+
+// SNAP_INSTALL_001: --help - print detailed help text for the install command
+func (s *installSuite) TestInstallShowHelp(c *check.C) {
+ expected := "(?ms)" +
+ "^Usage:\n" +
+ ` snap \[OPTIONS\] install.*\n` +
+ "\n^The install command .*\n" +
+ "^Help Options:\n" +
+ "^ -h, --help +Show this help message\n" +
+ ".*"
+
+ actual := cli.ExecCommand(c, "snap", "install", "--help")
+
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_INSTALL_002: without snap name shows error
+func (s *installSuite) TestInstallWithoutSnapNameMustPrintError(c *check.C) {
+ expected := "error: the required argument `` was not provided\n"
+
+ actual, err := cli.ExecCommandErr("snap", "install")
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_INSTALL_004: with already installed snap name and same version
+func (s *installSuite) TestInstallWithAlreadyInstalledSnapAndSameVersionMustFail(c *check.C) {
+ snapName := "hello-world"
+
+ common.InstallSnap(c, snapName)
+ defer common.RemoveSnap(c, snapName)
+
+ expected := fmt.Sprintf(`error: cannot install "%s": snap "%[1]s" already installed\n`, snapName)
+ actual, err := cli.ExecCommandErr("sudo", "snap", "install", snapName)
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_INSTALL_008: from different channel other than default
+func (s *installSuite) TestInstallFromDifferentChannels(c *check.C) {
+ snapName := "hello-world"
+
+ expected := "(?ms).*\n" +
+ "Name +Version +Rev +Developer +Notes\n" +
+ snapName + " .* canonical +-\n"
+
+ for _, channel := range []string{"edge", "beta", "candidate", "stable"} {
+ actual := cli.ExecCommand(c, "sudo", "snap", "install", snapName, "--channel="+channel)
+
+ c.Check(actual, check.Matches, expected)
+
+ common.RemoveSnap(c, snapName)
+ }
+}
+
+// SNAP_INSTALL_009: with devmode option
+func (s *installSuite) TestInstallWithDevmodeOption(c *check.C) {
+ snapName := "hello-world"
+
+ expected := "(?ms).*\n" +
+ "Name +Version +Rev +Developer +Notes\n" +
+ snapName + " .* canonical +devmode\n"
+
+ actual := cli.ExecCommand(c, "sudo", "snap", "install", snapName, "--devmode")
+ defer common.RemoveSnap(c, snapName)
+
+ c.Assert(actual, check.Matches, expected)
+}
+
+func (s *installSuite) TestInstallsDesktopFile(c *check.C) {
+ snapPath, err := build.LocalSnap(c, data.BasicDesktopSnapName)
+ defer os.Remove(snapPath)
+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
+ common.InstallSnap(c, snapPath)
+ defer common.RemoveSnap(c, data.BasicDesktopSnapName)
+
+ content, err := ioutil.ReadFile(filepath.Join(dirs.SnapDesktopFilesDir, "basic-desktop_echo.desktop"))
+ c.Assert(err, check.IsNil)
+ c.Assert(string(content), testutil.Contains, `[Desktop Entry]
+Name=Echo
+Comment=It echos stuff
+Exec=/snap/bin/basic-desktop.echo
+`)
+}
+
+// regression test for lp #1574829
+func (s *installSuite) TestInstallsPointsToLoginWhenNotAuthenticated(c *check.C) {
+ cli.ExecCommandErr("snap", "logout")
+
+ expected := ".*snap login --help.*\n"
+
+ actual, err := cli.ExecCommandErr("snap", "install", "hello-world")
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
diff -Nru snapd-2.0.5/integration-tests/tests/snap_known_test.go snapd-2.0.8/integration-tests/tests/snap_known_test.go
--- snapd-2.0.5/integration-tests/tests/snap_known_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_known_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,9 +26,9 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
)
var _ = check.Suite(&snapKnownSuite{})
diff -Nru snapd-2.0.5/integration-tests/tests/snap_op_test.go snapd-2.0.8/integration-tests/tests/snap_op_test.go
--- snapd-2.0.5/integration-tests/tests/snap_op_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_op_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,14 +29,14 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/build"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/wait"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/integration-tests/testutils/build"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/integration-tests/testutils/wait"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/testutil"
)
var _ = check.Suite(&snapOpSuite{})
@@ -48,7 +48,7 @@
func (s *snapOpSuite) testInstallRemove(c *check.C, snapName, displayName string) {
installOutput := common.InstallSnap(c, snapName)
expected := "(?ms)" +
- "Name +Version +Rev +Developer\n" +
+ "Name +Version +Rev +Developer +Notes\n" +
".*" +
displayName + " +.*\n" +
".*"
@@ -71,8 +71,8 @@
common.InstallSnap(c, snapPath)
installOutput := common.InstallSnap(c, snapPath)
c.Assert(installOutput, testutil.Contains, data.BasicSnapName)
- // double check, sideloaded snaps have revnos like 1000xx
- revnos, _ := filepath.Glob(filepath.Join(dirs.SnapSnapsDir, data.BasicSnapName, "1*"))
+ // double check, sideloaded snaps have revnos like xNN
+ revnos, _ := filepath.Glob(filepath.Join(dirs.SnapSnapsDir, data.BasicSnapName, "x*"))
c.Check(len(revnos) >= 2, check.Equals, true)
removeOutput := common.RemoveSnap(c, data.BasicSnapName)
@@ -108,10 +108,10 @@
wait.ForCommand(c, needle, "snap", "changes")
// find change id of the remove
- output := cli.ExecCommand(c, "snap", "changes")
+ output := cli.ExecCommand(c, "snap", "changes", data.BasicBinariesSnapName)
id := regexp.MustCompile(`(?m)([0-9]+).*Doing.*Remove.*"`).FindStringSubmatch(output)[1]
needle = `will retry: `
- wait.ForCommand(c, needle, "snap", "changes", id)
+ wait.ForCommand(c, needle, "snap", "change", id)
// now stop the service that blocks the umount
cli.ExecCommand(c, "sudo", "systemctl", "stop", blockerSrv)
@@ -153,11 +153,11 @@
c.Assert(err, check.NotNil)
// check undone and error in tasks
- output := cli.ExecCommand(c, "snap", "changes")
+ output := cli.ExecCommand(c, "snap", "changes", snapName)
expected := fmt.Sprintf(`(?ms).*\n(\d+) +Error.*Install "%s" snap\n$`, snapName)
id := regexp.MustCompile(expected).FindStringSubmatch(output)[1]
- output = cli.ExecCommand(c, "snap", "changes", id)
+ output = cli.ExecCommand(c, "snap", "change", id)
type undoneCheckerFunc func(*check.C, string, string)
for _, fn := range []undoneCheckerFunc{
diff -Nru snapd-2.0.5/integration-tests/tests/snap_persists_test.go snapd-2.0.8/integration-tests/tests/snap_persists_test.go
--- snapd-2.0.5/integration-tests/tests/snap_persists_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_persists_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,10 +23,10 @@
import (
"os"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/build"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/integration-tests/testutils/build"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/snap_refresh_all_test.go snapd-2.0.8/integration-tests/tests/snap_refresh_all_test.go
--- snapd-2.0.5/integration-tests/tests/snap_refresh_all_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_refresh_all_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,69 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration,!excludereboots,!classic
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "fmt"
+ "io/ioutil"
+
+ "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
+ "github.com/snapcore/snapd/integration-tests/testutils/refresh"
+ "github.com/snapcore/snapd/integration-tests/testutils/store"
+)
+
+var _ = check.Suite(&snapRefreshAllSuite{})
+
+type snapRefreshAllSuite struct {
+ common.SnappySuite
+}
+
+func (s *snapRefreshAllSuite) TestAllRefresh(c *check.C) {
+ // install two snaps and also create fake refresh
+ snaps := []string{"hello-world", "xkcd-webserver"}
+ for _, snap := range snaps {
+ cli.ExecCommand(c, "sudo", "snap", "install", snap)
+ defer cli.ExecCommand(c, "sudo", "snap", "remove", snap)
+ }
+
+ // create/start the store, run snapd against the fake store
+ blobDir, err := ioutil.TempDir("", "snap-fake-store-blobs-")
+ fakeStore := store.NewStore(blobDir)
+ err = fakeStore.Start()
+ c.Assert(err, check.IsNil)
+ defer fakeStore.Stop()
+
+ env := fmt.Sprintf(`SNAPPY_FORCE_CPI_URL=%s`, fakeStore.URL())
+ cfg, _ := config.ReadConfig(config.DefaultFileName)
+
+ tearDownSnapd(c)
+ defer setUpSnapd(c, cfg.FromBranch, "")
+ setUpSnapd(c, cfg.FromBranch, env)
+ defer tearDownSnapd(c)
+
+ // and refresh all snaps
+ output := refresh.CallFakeSnapRefreshAll(c, snaps, refresh.NoOp, fakeStore)
+ c.Assert(output, check.Matches, "(?ms).*^hello-world.*fake1.*")
+ c.Assert(output, check.Matches, "(?ms).*^xkcd-webserver.*fake1.*")
+}
diff -Nru snapd-2.0.5/integration-tests/tests/snap_refresh_app_test.go snapd-2.0.8/integration-tests/tests/snap_refresh_app_test.go
--- snapd-2.0.5/integration-tests/tests/snap_refresh_app_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_refresh_app_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,72 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration,!excludereboots,!classic
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "fmt"
+ "io/ioutil"
+
+ "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
+ "github.com/snapcore/snapd/integration-tests/testutils/refresh"
+ "github.com/snapcore/snapd/integration-tests/testutils/store"
+)
+
+var _ = check.Suite(&snapRefreshAppSuite{})
+
+type snapRefreshAppSuite struct {
+ common.SnappySuite
+}
+
+func (s *snapRefreshAppSuite) TestAppRefresh(c *check.C) {
+ snap := "hello-world"
+
+ // install edge version from the store (which is squashfs)
+ cli.ExecCommand(c, "sudo", "snap", "install", snap)
+ defer cli.ExecCommand(c, "sudo", "snap", "remove", snap)
+
+ // make a fakestore and make it available to snapd
+
+ // use /var/tmp is not a tempfs for space reasons
+ blobDir, err := ioutil.TempDir("/var/tmp", "snap-fake-store-blobs-")
+ c.Assert(err, check.IsNil)
+ defer cli.ExecCommand(c, "sudo", "rm", "-rf", blobDir)
+
+ fakeStore := store.NewStore(blobDir)
+ err = fakeStore.Start()
+ c.Assert(err, check.IsNil)
+ defer fakeStore.Stop()
+
+ env := fmt.Sprintf(`SNAPPY_FORCE_CPI_URL=%s`, fakeStore.URL())
+ cfg, _ := config.ReadConfig(config.DefaultFileName)
+
+ tearDownSnapd(c)
+ defer setUpSnapd(c, cfg.FromBranch, "")
+ setUpSnapd(c, cfg.FromBranch, env)
+ defer tearDownSnapd(c)
+
+ // run the fake refresh
+ output := refresh.CallFakeSnapRefreshForSnap(c, snap, refresh.NoOp, fakeStore)
+ c.Assert(output, check.Matches, "(?ms).*^hello-world.*fake1.*")
+}
diff -Nru snapd-2.0.5/integration-tests/tests/snap_remove_test.go snapd-2.0.8/integration-tests/tests/snap_remove_test.go
--- snapd-2.0.5/integration-tests/tests/snap_remove_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_remove_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,73 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "fmt"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+
+ "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&removeSuite{})
+
+type removeSuite struct {
+ common.SnappySuite
+}
+
+// SNAP_REMOVE_001: --help prints the detailed help test for the command
+func (s *removeSuite) TestRemoveShowsHelp(c *check.C) {
+ expected := "(?ms)" +
+ "^Usage:\n" +
+ ` snap \[OPTIONS\] remove.*\n` +
+ "\n^The remove command .*\n" +
+ "^Help Options:\n" +
+ "^ -h, --help +Show this help message\n" +
+ ".*"
+
+ actual := cli.ExecCommand(c, "snap", "remove", "--help")
+
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_REMOVE_002: - invalid pkg name
+func (s *removeSuite) TestRemoveInvalidPackageShowsError(c *check.C) {
+ invalidPkg := "invalid-package-name"
+
+ expected := fmt.Sprintf(`error: cannot remove "%s": cannot find snap "%[1]s"\n`, invalidPkg)
+
+ actual, err := cli.ExecCommandErr("sudo", "snap", "remove", invalidPkg)
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
+
+// SNAP_REMOVE_007: - ubuntu-core
+func (s *removeSuite) TestRemoveUbuntuCoreShowsError(c *check.C) {
+ expected := `error: cannot remove "ubuntu-core": snap "ubuntu-core" is not removable\n`
+
+ actual, err := cli.ExecCommandErr("sudo", "snap", "remove", "ubuntu-core")
+
+ c.Assert(err, check.NotNil)
+ c.Assert(actual, check.Matches, expected)
+}
diff -Nru snapd-2.0.5/integration-tests/tests/snap_update_app_test.go snapd-2.0.8/integration-tests/tests/snap_update_app_test.go
--- snapd-2.0.5/integration-tests/tests/snap_update_app_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/snap_update_app_test.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration,!excludereboots
-
-/*
- * Copyright (C) 2016 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package tests
-
-import (
- "fmt"
- "io/ioutil"
-
- "gopkg.in/check.v1"
-
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/config"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/store"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/updates"
-)
-
-var _ = check.Suite(&snapRefreshAppSuite{})
-
-type snapRefreshAppSuite struct {
- common.SnappySuite
-}
-
-func (s *snapRefreshAppSuite) TestAppUpdate(c *check.C) {
- snap := "hello-world"
-
- // install edge version from the store (which is squashfs)
- cli.ExecCommand(c, "sudo", "snap", "install", snap)
- defer cli.ExecCommand(c, "sudo", "snap", "remove", snap)
-
- // make a fakestore and make it available to snapd
-
- // use /var/tmp is not a tempfs for space reasons
- blobDir, err := ioutil.TempDir("/var/tmp", "snap-fake-store-blobs-")
- c.Assert(err, check.IsNil)
- defer cli.ExecCommand(c, "sudo", "rm", "-rf", blobDir)
-
- fakeStore := store.NewStore(blobDir)
- err = fakeStore.Start()
- c.Assert(err, check.IsNil)
- defer fakeStore.Stop()
-
- env := fmt.Sprintf(`SNAPPY_FORCE_CPI_URL=%s`, fakeStore.URL())
- cfg, _ := config.ReadConfig(config.DefaultFileName)
-
- tearDownSnapd(c)
- defer setUpSnapd(c, cfg.FromBranch, "")
- setUpSnapd(c, cfg.FromBranch, env)
- defer tearDownSnapd(c)
-
- // run the fake update
- output := updates.CallFakeSnapRefresh(c, snap, updates.NoOp, fakeStore)
- c.Assert(output, check.Matches, "(?ms).*^hello-world.*fake1.*")
-}
diff -Nru snapd-2.0.5/integration-tests/tests/tryapp_test.go snapd-2.0.8/integration-tests/tests/tryapp_test.go
--- snapd-2.0.5/integration-tests/tests/tryapp_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/tryapp_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,109 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration
+
+/*
+ * Copyright (C) 2015, 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "os"
+ "path/filepath"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/build"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/testutil"
+
+ "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&trySuite{})
+
+type trySuite struct {
+ common.SnappySuite
+}
+
+func (s *trySuite) TestTryBasicBinaries(c *check.C) {
+ tryPath, err := filepath.Abs(filepath.Join(data.BaseSnapPath, data.BasicBinariesSnapName))
+ c.Assert(err, check.IsNil)
+
+ tryOutput := cli.ExecCommand(c, "sudo", "snap", "try", tryPath)
+ defer common.RemoveSnap(c, data.BasicBinariesSnapName)
+
+ expected := "(?ms)" +
+ ".*" +
+ "Name +Version +Rev +Developer +Notes\n" +
+ "basic-binaries +.*try"
+ c.Check(tryOutput, check.Matches, expected)
+
+ // can run commands from the snap-try binary
+ cli.ExecCommand(c, "basic-binaries.success")
+
+ // commands can read stuff in their own dir
+ output := cli.ExecCommand(c, "basic-binaries.cat")
+ c.Check(output, testutil.Contains, "I output myself")
+}
+
+func (s *trySuite) TestTryConfinmentDenies(c *check.C) {
+ tryPath, err := filepath.Abs(filepath.Join(data.BaseSnapPath, data.DevKmsg))
+ c.Assert(err, check.IsNil)
+
+ cli.ExecCommand(c, "sudo", "snap", "try", tryPath)
+ defer common.RemoveSnap(c, data.DevKmsg)
+
+ // confinment works in try mode:
+ // dev-kmsg.reader can not read /dev/kmsg out of the box
+ output, err := cli.ExecCommandErr("dev-kmsg.reader")
+ c.Check(err, check.NotNil)
+ c.Check(output, check.Matches, `(?ms)dd: failed to open '/dev/kmsg': Permission denied`)
+}
+
+func (s *trySuite) TestTryConfinmentDevModeAllows(c *check.C) {
+ tryPath, err := filepath.Abs(filepath.Join(data.BaseSnapPath, data.DevKmsg))
+ c.Assert(err, check.IsNil)
+
+ cli.ExecCommand(c, "sudo", "snap", "try", "--devmode", tryPath)
+ defer common.RemoveSnap(c, data.DevKmsg)
+
+ // dev-mode disables confinement and we can read /dev/kmsg
+ output, err := cli.ExecCommandErr("dev-kmsg.reader")
+ c.Check(err, check.IsNil)
+ c.Check(output, check.Not(check.HasLen), 0)
+}
+
+func (s *trySuite) TestTryConfinmentAllows(c *check.C) {
+ // provide a server for the test
+ snapPath, err := build.LocalSnap(c, data.NetworkBindConsumerSnapName)
+ c.Assert(err, check.IsNil)
+ defer os.Remove(snapPath)
+ common.InstallSnap(c, snapPath)
+ defer common.RemoveSnap(c, data.NetworkBindConsumerSnapName)
+
+ // "try" client confinment (network auto-connects)
+ tryPath, err := filepath.Abs(filepath.Join(data.BaseSnapPath, data.NetworkConsumerSnapName))
+ c.Assert(err, check.IsNil)
+
+ cli.ExecCommand(c, "sudo", "snap", "try", tryPath)
+ defer common.RemoveSnap(c, data.NetworkConsumerSnapName)
+
+ // confinment works in try mode:
+ providerURL := "http://127.0.0.1:8081"
+ output := cli.ExecCommand(c, "network-consumer", providerURL)
+ c.Assert(output, check.Equals, "ok\n")
+}
diff -Nru snapd-2.0.5/integration-tests/tests/ubuntufan_test.go snapd-2.0.8/integration-tests/tests/ubuntufan_test.go
--- snapd-2.0.5/integration-tests/tests/ubuntufan_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/ubuntufan_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,220 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration,!lowperformance,!classic
+
+/*
+ * Copyright (C) 2015, 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "fmt"
+ "net"
+ "os/exec"
+ "strings"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/wait"
+
+ "gopkg.in/check.v1"
+)
+
+const (
+ firstOverlaySegment = "241"
+ baseContainer = "busybox"
+)
+
+var _ = check.Suite(&fanTestSuite{})
+
+type fanTestSuite struct {
+ common.SnappySuite
+ bridgeIP string
+ subjectIP string
+}
+
+func (s *fanTestSuite) SetUpTest(c *check.C) {
+ if common.Release(c) == "15.04" {
+ c.Skip("Ubuntu Fan not available in 15.04")
+ }
+
+ s.SnappySuite.SetUpTest(c)
+ var err error
+ s.subjectIP, err = getIPAddr(c)
+ c.Assert(err, check.IsNil, check.Commentf("Error getting IP address: %s", err))
+
+ s.fanCtl(c, "up")
+ s.bridgeIP = s.fanBridgeIP(c)
+}
+
+func (s *fanTestSuite) TearDownTest(c *check.C) {
+ s.SnappySuite.TearDownTest(c)
+
+ s.fanCtl(c, "down")
+}
+
+func (s *fanTestSuite) TestFanCommandExists(c *check.C) {
+ cmd := exec.Command("fanctl")
+ output, _ := cmd.CombinedOutput()
+
+ expectedPattern := `(?msi)Usage: \/usr\/sbin\/fanctl .*`
+
+ c.Assert(string(output), check.Matches, expectedPattern,
+ check.Commentf("Expected output pattern %s not found in %s", expectedPattern, output))
+}
+
+func (s *fanTestSuite) TestFanCommandCreatesFanBridge(c *check.C) {
+ output := cli.ExecCommand(c, "ifconfig")
+
+ expectedPattern := fmt.Sprintf("(?msi).*%s.*%s.*", s.fanName(), s.bridgeIP)
+
+ c.Assert(output, check.Matches, expectedPattern,
+ check.Commentf("Expected pattern %s not found in %s", expectedPattern, output))
+}
+
+func (s *fanTestSuite) TestDockerCreatesAContainerInsideTheFan(c *check.C) {
+ c.Skip("Skipping until LP: #1544507 is fixed")
+
+ setUpDocker(c)
+ defer tearDownDocker(c)
+ s.configureDockerToUseBridge(c)
+ defer s.removeBridgeFromDockerConf(c)
+
+ output := cli.ExecCommand(c, "docker", "run", "-t", baseContainer, "ifconfig")
+
+ expectedIP := strings.TrimRight(s.bridgeIP, ".1") + ".2"
+ expectedPattern := fmt.Sprintf("(?ms).*inet addr:%s.*", expectedIP)
+
+ c.Assert(output, check.Matches, expectedPattern,
+ check.Commentf("Expected pattern %s not found in %s", expectedPattern, output))
+}
+
+func (s *fanTestSuite) TestContainersInTheFanAreReachable(c *check.C) {
+ c.Skip("Skipping until LP: #1544507 is fixed")
+
+ setUpDocker(c)
+ defer tearDownDocker(c)
+ s.configureDockerToUseBridge(c)
+ defer s.removeBridgeFromDockerConf(c)
+
+ // spin up first container
+ cli.ExecCommand(c, "docker", "run", "-d", "-t", baseContainer)
+ // the first assigned IP in the fan will end with ".2"
+ firstIPAddr := strings.TrimRight(s.bridgeIP, ".1") + ".2"
+
+ // ping from a second container
+ output := cli.ExecCommand(c, "docker", "run", "-t", baseContainer, "ping", firstIPAddr, "-c", "1")
+
+ expectedPattern := "(?ms).*1 packets transmitted, 1 packets received, 0% packet loss.*"
+
+ c.Assert(output, check.Matches, expectedPattern,
+ check.Commentf("Expected pattern %s not found in %s", expectedPattern, output))
+}
+
+func getIPAddr(c *check.C) (ip string, err error) {
+ if ips, err := net.InterfaceAddrs(); err == nil {
+ for _, addr := range ips {
+ hostport := addr.String()
+ // poor's man check for ipv6
+ if !strings.Contains(hostport, ":") &&
+ !strings.Contains(hostport, "127.0.0.1") {
+ parts := strings.Split(hostport, "/")
+ return parts[0], nil
+ }
+ }
+ }
+ return
+}
+
+func (s *fanTestSuite) fanBridgeIP(c *check.C) (bridgeIP string) {
+ segments := strings.Split(s.subjectIP, ".")
+
+ // the final bridge ip is formed by the given overlay first segment, the last two from
+ // the interface ip and "1" at the end
+ return strings.Join([]string{firstOverlaySegment, segments[2], segments[3], "1"}, ".")
+}
+
+func (s *fanTestSuite) fanCtl(c *check.C, cmd string) string {
+ return cli.ExecCommand(c,
+ "sudo", "fanctl", cmd, firstOverlaySegment+".0.0.0/8", s.subjectIP+"/16")
+}
+
+func (s *fanTestSuite) configureDockerToUseBridge(c *check.C) {
+ cfgFile := dockerCfgFile(c)
+
+ cli.ExecCommand(c, "sudo", "sed", "-i",
+ fmt.Sprintf(`s/DOCKER_OPTIONS=\"\"/DOCKER_OPTIONS=\"%s\"/`, s.dockerOptions()),
+ cfgFile)
+
+ restartDocker(c)
+}
+
+func (s *fanTestSuite) removeBridgeFromDockerConf(c *check.C) {
+ cfgFile := dockerCfgFile(c)
+
+ cli.ExecCommand(c, "sudo", "sed", "-i",
+ `s/DOCKER_OPTIONS=\".*\"/DOCKER_OPTIONS=\"\"/`,
+ cfgFile)
+
+ restartDocker(c)
+}
+
+func dockerCfgFile(c *check.C) string {
+ dockerVersion := common.GetCurrentVersion(c, "docker")
+ return fmt.Sprintf("/var/snap/docker/%s/etc/docker.conf", dockerVersion)
+}
+
+func restartDocker(c *check.C) {
+ dockerVersion := common.GetCurrentVersion(c, "docker")
+ dockerService := fmt.Sprintf("docker_docker-daemon_%s.service", dockerVersion)
+
+ cli.ExecCommand(c, "sudo", "systemctl", "restart", dockerService)
+
+ // we need to wait until the socket is ready, an active systemctl status is not enough
+ err := wait.ForActiveService(c, dockerService)
+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
+
+ err = wait.ForCommand(c, `(?ms).*docker\.sock\s.*`, "ls", "/run")
+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
+}
+
+func (s *fanTestSuite) fanName() string {
+ firstOctect := strings.Split(s.bridgeIP, ".")[0]
+
+ return "fan-" + firstOctect
+}
+
+func (s *fanTestSuite) dockerOptions() string {
+ return fmt.Sprintf("-d -b %s --mtu=1480 --iptables=false", s.fanName())
+}
+
+func setUpDocker(c *check.C) {
+ common.InstallSnap(c, "docker/edge")
+ dockerVersion := common.GetCurrentVersion(c, "docker")
+ dockerService := fmt.Sprintf("docker_docker-daemon_%s.service", dockerVersion)
+
+ err := wait.ForActiveService(c, dockerService)
+ c.Assert(err, check.IsNil, check.Commentf("Error waiting for service: %s", err))
+
+ err = wait.ForCommand(c, `(?ms).*docker\.sock\s.*`, "ls", "/run")
+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
+
+ cli.ExecCommand(c, "docker", "pull", baseContainer)
+}
+
+func tearDownDocker(c *check.C) {
+ common.RemoveSnap(c, "docker")
+}
diff -Nru snapd-2.0.5/integration-tests/tests/ubuntuFan_test.go snapd-2.0.8/integration-tests/tests/ubuntuFan_test.go
--- snapd-2.0.5/integration-tests/tests/ubuntuFan_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/ubuntuFan_test.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,220 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration,!lowperformance
-
-/*
- * Copyright (C) 2015 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package tests
-
-import (
- "fmt"
- "net"
- "os/exec"
- "strings"
-
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/wait"
-
- "gopkg.in/check.v1"
-)
-
-const (
- firstOverlaySegment = "241"
- baseContainer = "busybox"
-)
-
-var _ = check.Suite(&fanTestSuite{})
-
-type fanTestSuite struct {
- common.SnappySuite
- bridgeIP string
- subjectIP string
-}
-
-func (s *fanTestSuite) SetUpTest(c *check.C) {
- if common.Release(c) == "15.04" {
- c.Skip("Ubuntu Fan not available in 15.04")
- }
-
- s.SnappySuite.SetUpTest(c)
- var err error
- s.subjectIP, err = getIPAddr(c)
- c.Assert(err, check.IsNil, check.Commentf("Error getting IP address: %s", err))
-
- s.fanCtl(c, "up")
- s.bridgeIP = s.fanBridgeIP(c)
-}
-
-func (s *fanTestSuite) TearDownTest(c *check.C) {
- s.SnappySuite.TearDownTest(c)
-
- s.fanCtl(c, "down")
-}
-
-func (s *fanTestSuite) TestFanCommandExists(c *check.C) {
- cmd := exec.Command("fanctl")
- output, _ := cmd.CombinedOutput()
-
- expectedPattern := `(?msi)Usage: \/usr\/sbin\/fanctl .*`
-
- c.Assert(string(output), check.Matches, expectedPattern,
- check.Commentf("Expected output pattern %s not found in %s", expectedPattern, output))
-}
-
-func (s *fanTestSuite) TestFanCommandCreatesFanBridge(c *check.C) {
- output := cli.ExecCommand(c, "ifconfig")
-
- expectedPattern := fmt.Sprintf("(?msi).*%s.*%s.*", s.fanName(), s.bridgeIP)
-
- c.Assert(output, check.Matches, expectedPattern,
- check.Commentf("Expected pattern %s not found in %s", expectedPattern, output))
-}
-
-func (s *fanTestSuite) TestDockerCreatesAContainerInsideTheFan(c *check.C) {
- c.Skip("Skipping until LP: #1544507 is fixed")
-
- setUpDocker(c)
- defer tearDownDocker(c)
- s.configureDockerToUseBridge(c)
- defer s.removeBridgeFromDockerConf(c)
-
- output := cli.ExecCommand(c, "docker", "run", "-t", baseContainer, "ifconfig")
-
- expectedIP := strings.TrimRight(s.bridgeIP, ".1") + ".2"
- expectedPattern := fmt.Sprintf("(?ms).*inet addr:%s.*", expectedIP)
-
- c.Assert(output, check.Matches, expectedPattern,
- check.Commentf("Expected pattern %s not found in %s", expectedPattern, output))
-}
-
-func (s *fanTestSuite) TestContainersInTheFanAreReachable(c *check.C) {
- c.Skip("Skipping until LP: #1544507 is fixed")
-
- setUpDocker(c)
- defer tearDownDocker(c)
- s.configureDockerToUseBridge(c)
- defer s.removeBridgeFromDockerConf(c)
-
- // spin up first container
- cli.ExecCommand(c, "docker", "run", "-d", "-t", baseContainer)
- // the first assigned IP in the fan will end with ".2"
- firstIPAddr := strings.TrimRight(s.bridgeIP, ".1") + ".2"
-
- // ping from a second container
- output := cli.ExecCommand(c, "docker", "run", "-t", baseContainer, "ping", firstIPAddr, "-c", "1")
-
- expectedPattern := "(?ms).*1 packets transmitted, 1 packets received, 0% packet loss.*"
-
- c.Assert(output, check.Matches, expectedPattern,
- check.Commentf("Expected pattern %s not found in %s", expectedPattern, output))
-}
-
-func getIPAddr(c *check.C) (ip string, err error) {
- if ips, err := net.InterfaceAddrs(); err == nil {
- for _, addr := range ips {
- hostport := addr.String()
- // poor's man check for ipv6
- if !strings.Contains(hostport, ":") &&
- !strings.Contains(hostport, "127.0.0.1") {
- parts := strings.Split(hostport, "/")
- return parts[0], nil
- }
- }
- }
- return
-}
-
-func (s *fanTestSuite) fanBridgeIP(c *check.C) (bridgeIP string) {
- segments := strings.Split(s.subjectIP, ".")
-
- // the final bridge ip is formed by the given overlay first segment, the last two from
- // the interface ip and "1" at the end
- return strings.Join([]string{firstOverlaySegment, segments[2], segments[3], "1"}, ".")
-}
-
-func (s *fanTestSuite) fanCtl(c *check.C, cmd string) string {
- return cli.ExecCommand(c,
- "sudo", "fanctl", cmd, firstOverlaySegment+".0.0.0/8", s.subjectIP+"/16")
-}
-
-func (s *fanTestSuite) configureDockerToUseBridge(c *check.C) {
- cfgFile := dockerCfgFile(c)
-
- cli.ExecCommand(c, "sudo", "sed", "-i",
- fmt.Sprintf(`s/DOCKER_OPTIONS=\"\"/DOCKER_OPTIONS=\"%s\"/`, s.dockerOptions()),
- cfgFile)
-
- restartDocker(c)
-}
-
-func (s *fanTestSuite) removeBridgeFromDockerConf(c *check.C) {
- cfgFile := dockerCfgFile(c)
-
- cli.ExecCommand(c, "sudo", "sed", "-i",
- `s/DOCKER_OPTIONS=\".*\"/DOCKER_OPTIONS=\"\"/`,
- cfgFile)
-
- restartDocker(c)
-}
-
-func dockerCfgFile(c *check.C) string {
- dockerVersion := common.GetCurrentVersion(c, "docker")
- return fmt.Sprintf("/var/snap/docker/%s/etc/docker.conf", dockerVersion)
-}
-
-func restartDocker(c *check.C) {
- dockerVersion := common.GetCurrentVersion(c, "docker")
- dockerService := fmt.Sprintf("docker_docker-daemon_%s.service", dockerVersion)
-
- cli.ExecCommand(c, "sudo", "systemctl", "restart", dockerService)
-
- // we need to wait until the socket is ready, an active systemctl status is not enough
- err := wait.ForActiveService(c, dockerService)
- c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
-
- err = wait.ForCommand(c, `(?ms).*docker\.sock\s.*`, "ls", "/run")
- c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
-}
-
-func (s *fanTestSuite) fanName() string {
- firstOctect := strings.Split(s.bridgeIP, ".")[0]
-
- return "fan-" + firstOctect
-}
-
-func (s *fanTestSuite) dockerOptions() string {
- return fmt.Sprintf("-d -b %s --mtu=1480 --iptables=false", s.fanName())
-}
-
-func setUpDocker(c *check.C) {
- common.InstallSnap(c, "docker/edge")
- dockerVersion := common.GetCurrentVersion(c, "docker")
- dockerService := fmt.Sprintf("docker_docker-daemon_%s.service", dockerVersion)
-
- err := wait.ForActiveService(c, dockerService)
- c.Assert(err, check.IsNil, check.Commentf("Error waiting for service: %s", err))
-
- err = wait.ForCommand(c, `(?ms).*docker\.sock\s.*`, "ls", "/run")
- c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
-
- cli.ExecCommand(c, "docker", "pull", baseContainer)
-}
-
-func tearDownDocker(c *check.C) {
- common.RemoveSnap(c, "docker")
-}
diff -Nru snapd-2.0.5/integration-tests/tests/unity_test.go snapd-2.0.8/integration-tests/tests/unity_test.go
--- snapd-2.0.5/integration-tests/tests/unity_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/unity_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -1,5 +1,5 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration,classiconly
+// +build !excludeintegration,!allsnaps
/*
* Copyright (C) 2016 Canonical Ltd
@@ -25,9 +25,9 @@
"os"
"os/exec"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/wait"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/wait"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/update_rollback_stress_test.go snapd-2.0.8/integration-tests/tests/update_rollback_stress_test.go
--- snapd-2.0.5/integration-tests/tests/update_rollback_stress_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/update_rollback_stress_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
"path/filepath"
"strconv"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
"gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/integration-tests/tests/writablepaths_test.go snapd-2.0.8/integration-tests/tests/writablepaths_test.go
--- snapd-2.0.5/integration-tests/tests/writablepaths_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/writablepaths_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,107 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration,!classic
+
+/*
+ * Copyright (C) 2015, 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tests
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
+
+ "gopkg.in/check.v1"
+)
+
+const writablePathsListFile = "/etc/system-image/writable-paths"
+
+var _ = check.Suite(&writablePathsSuite{})
+
+type writablePathsSuite struct {
+ common.SnappySuite
+}
+
+var IsWritable check.Checker = &isWritable{}
+
+type isWritable struct {
+}
+
+func (is *isWritable) Info() *check.CheckerInfo {
+ return &check.CheckerInfo{Name: "IsWritable", Params: []string{"path"}}
+}
+
+func (is *isWritable) Check(params []interface{}, names []string) (result bool, error string) {
+ if path, ok := params[0].(string); ok {
+ filename := filepath.Join(path, "tmpfile")
+
+ cmd := exec.Command("sudo", "touch", filename)
+ rmCmd := exec.Command("sudo", "rm", filename)
+ defer rmCmd.Run()
+
+ if _, err := cmd.CombinedOutput(); err == nil {
+ result = true
+ } else {
+ error = fmt.Sprintf("Error creating file %s", filename)
+ }
+ } else {
+ error = fmt.Sprintf("First param of checker %v is of type %T and it should be a string", params[0], params[0])
+ }
+ return result, error
+}
+
+func (s *writablePathsSuite) TestWritablePathsAreWritable(c *check.C) {
+ for writablePath := range generateWritablePaths(c) {
+ c.Logf("Checking if %s is writable", writablePath)
+ c.Check(writablePath, IsWritable)
+ }
+}
+
+func generateWritablePaths(c *check.C) chan string {
+ ch := make(chan string)
+
+ go func() {
+ file, err := os.Open(writablePathsListFile)
+
+ c.Assert(err, check.IsNil,
+ check.Commentf("Error reading writable files list %s", writablePathsListFile))
+
+ defer file.Close()
+
+ reader := bufio.NewReader(file)
+ scanner := bufio.NewScanner(reader)
+
+ scanner.Split(bufio.ScanLines)
+
+ for scanner.Scan() {
+ fields := strings.Fields(scanner.Text())
+ if len(fields) > 0 && fields[0] != "#" {
+ if src, err := os.Stat(fields[0]); err == nil && src.IsDir() {
+ ch <- fields[0]
+ }
+ }
+ }
+ close(ch)
+ }()
+
+ return ch
+}
diff -Nru snapd-2.0.5/integration-tests/tests/writablePaths_test.go snapd-2.0.8/integration-tests/tests/writablePaths_test.go
--- snapd-2.0.5/integration-tests/tests/writablePaths_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/tests/writablePaths_test.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,107 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration
-
-/*
- * Copyright (C) 2015 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package tests
-
-import (
- "bufio"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
-
- "gopkg.in/check.v1"
-)
-
-const writablePathsListFile = "/etc/system-image/writable-paths"
-
-var _ = check.Suite(&writablePathsSuite{})
-
-type writablePathsSuite struct {
- common.SnappySuite
-}
-
-var IsWritable check.Checker = &isWritable{}
-
-type isWritable struct {
-}
-
-func (is *isWritable) Info() *check.CheckerInfo {
- return &check.CheckerInfo{Name: "IsWritable", Params: []string{"path"}}
-}
-
-func (is *isWritable) Check(params []interface{}, names []string) (result bool, error string) {
- if path, ok := params[0].(string); ok {
- filename := filepath.Join(path, "tmpfile")
-
- cmd := exec.Command("sudo", "touch", filename)
- rmCmd := exec.Command("sudo", "rm", filename)
- defer rmCmd.Run()
-
- if _, err := cmd.CombinedOutput(); err == nil {
- result = true
- } else {
- error = fmt.Sprintf("Error creating file %s", filename)
- }
- } else {
- error = fmt.Sprintf("First param of checker %v is of type %T and it should be a string", params[0], params[0])
- }
- return result, error
-}
-
-func (s *writablePathsSuite) TestWritablePathsAreWritable(c *check.C) {
- for writablePath := range generateWritablePaths(c) {
- c.Logf("Checking if %s is writable", writablePath)
- c.Check(writablePath, IsWritable)
- }
-}
-
-func generateWritablePaths(c *check.C) chan string {
- ch := make(chan string)
-
- go func() {
- file, err := os.Open(writablePathsListFile)
-
- c.Assert(err, check.IsNil,
- check.Commentf("Error reading writable files list %s", writablePathsListFile))
-
- defer file.Close()
-
- reader := bufio.NewReader(file)
- scanner := bufio.NewScanner(reader)
-
- scanner.Split(bufio.ScanLines)
-
- for scanner.Scan() {
- fields := strings.Fields(scanner.Text())
- if len(fields) > 0 && fields[0] != "#" {
- if src, err := os.Stat(fields[0]); err == nil && src.IsDir() {
- ch <- fields[0]
- }
- }
- }
- close(ch)
- }()
-
- return ch
-}
diff -Nru snapd-2.0.5/integration-tests/testutils/autopkgtest/autopkgtest.go snapd-2.0.8/integration-tests/testutils/autopkgtest/autopkgtest.go
--- snapd-2.0.5/integration-tests/testutils/autopkgtest/autopkgtest.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/autopkgtest/autopkgtest.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,8 +25,8 @@
"path/filepath"
"strings"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/testutils"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/tpl"
+ "github.com/snapcore/snapd/integration-tests/testutils/testutils"
+ "github.com/snapcore/snapd/integration-tests/testutils/tpl"
)
const (
@@ -56,6 +56,8 @@
ShellOnFail bool
// Env is a map with the environment variables to set on the test bed and their values.
Env map[string]string
+ // Verbose controls the amount of output printed
+ Verbose bool
}
// AdtRunLocal starts a kvm running the image passed as argument and runs the
@@ -80,11 +82,15 @@
prepareTargetDir(outputDir)
cmd := []string{
- "adt-run", "-B",
+ "adt-run", "-B"}
+ if !a.Verbose {
+ cmd = append(cmd, "-q")
+ }
+ cmd = append(cmd, []string{
"--override-control", controlFile,
"--built-tree", a.SourceCodePath,
"--output-dir", outputDir,
- "--setup-commands", "touch /run/autopkgtest_no_reboot.stamp"}
+ "--setup-commands", "touch /run/autopkgtest_no_reboot.stamp"}...)
for envVar, value := range a.Env {
cmd = append(cmd, "--env")
cmd = append(cmd, fmt.Sprintf("%s=%s", envVar, value))
diff -Nru snapd-2.0.5/integration-tests/testutils/autopkgtest/autopkgtest_test.go snapd-2.0.8/integration-tests/testutils/autopkgtest/autopkgtest_test.go
--- snapd-2.0.5/integration-tests/testutils/autopkgtest/autopkgtest_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/autopkgtest/autopkgtest_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -43,7 +43,7 @@
imgPath = "imgPath"
testbedIP = "1.1.1.1"
testbedPort = 90
- adtrunTpl = "adt-run -B --override-control %s --built-tree %s --output-dir %s --setup-commands touch /run/autopkgtest_no_reboot.stamp %s"
+ adtrunTpl = "adt-run -B -q --override-control %s --built-tree %s --output-dir %s --setup-commands touch /run/autopkgtest_no_reboot.stamp %s"
)
type AutoPkgTestSuite struct {
@@ -224,6 +224,35 @@
check.Commentf("Expected call %s not executed 1 time", expectedCommandCall))
}
+func (s *AutoPkgTestSuite) TestAdtRunLocalAddsQuietFlag(c *check.C) {
+ s.adtRunAddsQuietFlag(c, true)
+}
+
+func (s *AutoPkgTestSuite) TestAdtRunRemoteAddsQuietFlag(c *check.C) {
+ s.adtRunAddsQuietFlag(c, false)
+}
+
+func (s *AutoPkgTestSuite) adtRunAddsQuietFlag(c *check.C, local bool) {
+ s.subject.Verbose = true
+
+ if local {
+ s.subject.AdtRunLocal(imgPath)
+ } else {
+ s.subject.AdtRunRemote(testbedIP, testbedPort)
+ }
+
+ match := false
+ for call := range s.execCalls {
+ if strings.HasPrefix(call, "adt-run") {
+ if strings.Contains(call, " -q ") {
+ match = true
+ break
+ }
+ }
+ }
+ c.Assert(match, check.Equals, false, check.Commentf("quiet flag found in adt-run call with verbose=true"))
+}
+
func tplExecuteCmd(tplFile, outputFile string, data interface{}) string {
return fmt.Sprint(tplFile, outputFile, data)
}
diff -Nru snapd-2.0.5/integration-tests/testutils/build/build.go snapd-2.0.8/integration-tests/testutils/build/build.go
--- snapd-2.0.5/integration-tests/testutils/build/build.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/build/build.go 2016-06-08 05:58:01.000000000 +0000
@@ -31,8 +31,8 @@
"runtime"
"strings"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/testutils"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/testutils"
)
const (
@@ -46,7 +46,7 @@
defaultGoArm = "7"
testsBinDir = "integration-tests/bin/"
baseBuildCmd = "go test -c -tags integrationcoverage "
- projectSrcPath = "src/github.com/ubuntu-core/snappy"
+ projectSrcPath = "src/github.com/snapcore/snapd"
)
var (
@@ -66,7 +66,7 @@
// Assets builds the snappy and integration tests binaries for the target
// architecture.
-func Assets(cfg *Config) {
+func Assets(cfg *Config) error {
tmp := "/tmp/snappy-build"
_, filename, _, _ := runtime.Caller(1)
dir, _ := filepath.Abs(filepath.Join(path.Dir(filename), ".."))
@@ -81,36 +81,42 @@
coverpkg := getCoverPkg()
// FIXME We need to build an image that has the snappy from the branch
// installed. --elopio - 2015-06-25.
- buildSnapd(cfg.Arch, coverpkg)
- buildSnapCLI(cfg.Arch, coverpkg)
+ if err := buildSnapd(cfg.Arch, coverpkg); err != nil {
+ return err
+ }
+ if err := buildSnapCLI(cfg.Arch, coverpkg); err != nil {
+ return err
+ }
+ }
+ if err := buildSnapbuild(cfg.Arch); err != nil {
+ return err
}
- buildSnapbuild(cfg.Arch)
- buildTests(cfg.Arch, cfg.TestBuildTags)
+ return buildTests(cfg.Arch, cfg.TestBuildTags)
}
-func buildSnapd(arch, coverpkg string) {
+func buildSnapd(arch, coverpkg string) error {
fmt.Println("Building snapd...")
buildSnapdCmd := getBinaryBuildCmd("snapd", coverpkg)
- goCall(arch, buildSnapdCmd)
+ return goCall(arch, buildSnapdCmd)
}
-func buildSnapCLI(arch, coverpkg string) {
+func buildSnapCLI(arch, coverpkg string) error {
fmt.Println("Building snap...")
buildSnapCliCmd := getBinaryBuildCmd("snap", coverpkg)
- goCall(arch, buildSnapCliCmd)
+ return goCall(arch, buildSnapCliCmd)
}
-func buildSnapbuild(arch string) {
+func buildSnapbuild(arch string) error {
fmt.Println("Building snapbuild...")
buildSnapbuildCmd := "go build" +
" -o " + filepath.Join(testsBinDir, filepath.Base(snapbuildPkg)) + " " + snapbuildPkg
- goCall(arch, buildSnapbuildCmd)
+ return goCall(arch, buildSnapbuildCmd)
}
-func buildTests(arch, testBuildTags string) {
+func buildTests(arch, testBuildTags string) error {
fmt.Println("Building tests...")
var tagText string
@@ -119,13 +125,15 @@
}
cmd := fmt.Sprintf(buildTestCmdFmt, tagText)
- goCall(arch, cmd)
+ if err := goCall(arch, cmd); err != nil {
+ return err
+ }
// XXX Go test 1.3 does not have the output flag, so we move the
// binaries after they are generated.
- osRename("tests.test", testsBinDir+IntegrationTestName)
+ return osRename("tests.test", testsBinDir+IntegrationTestName)
}
-func goCall(arch string, cmd string) {
+func goCall(arch string, cmd string) error {
if arch != "" {
defer osSetenv("GOARCH", osGetenv("GOARCH"))
osSetenv("GOARCH", arch)
@@ -144,7 +152,11 @@
cmdElems := strings.Fields(cmd)
command := exec.Command(cmdElems[0], cmdElems[1:]...)
command.Dir = filepath.Join(os.Getenv("GOPATH"), projectSrcPath)
- execCommand(command)
+ output, err := execCommand(command)
+ if err != nil {
+ return fmt.Errorf("command %q failed: %q (%s)", cmdElems, err, output)
+ }
+ return nil
}
func getBinaryBuildCmd(binary, coverpkg string) string {
@@ -175,8 +187,8 @@
// without filtering the helper, osutil and progress packages the compilation of the tests gives these errors:
// /home/fgimenez/src/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
// /tmp/go-link-492921396/000003.o: In function `_cgo_b95aca69b89e_Cfunc_isatty':
- // /home/fgimenez/workspace/gocode/src/github.com/ubuntu-core/snappy/progress/isatty.go:50: multiple definition of `_cgo_b95aca69b89e_Cfunc_isatty'
- // /tmp/go-link-492921396/000002.o:/home/fgimenez/workspace/gocode/src/github/ubuntu-core/snappy/progress/isatty.go:50: first defined here
+ // /home/fgimenez/workspace/gocode/src/github.com/snapcore/snapd/progress/isatty.go:50: multiple definition of `_cgo_b95aca69b89e_Cfunc_isatty'
+ // /tmp/go-link-492921396/000002.o:/home/fgimenez/workspace/gocode/src/github/snapcore/snapd/progress/isatty.go:50: first defined here
filterPattern := `.*integration-tests|helper|osutil|progress`
r := regexp.MustCompile(filterPattern)
diff -Nru snapd-2.0.5/integration-tests/testutils/build/snapbuild/main.go snapd-2.0.8/integration-tests/testutils/build/snapbuild/main.go
--- snapd-2.0.5/integration-tests/testutils/build/snapbuild/main.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/build/snapbuild/main.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
"fmt"
"os"
- "github.com/ubuntu-core/snappy/snap/snaptest"
+ "github.com/snapcore/snapd/snap/snaptest"
)
func main() {
diff -Nru snapd-2.0.5/integration-tests/testutils/build/snap.go snapd-2.0.8/integration-tests/testutils/build/snap.go
--- snapd-2.0.5/integration-tests/testutils/build/snap.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/build/snap.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,9 +25,9 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/snap/snaptest"
+ "github.com/snapcore/snapd/snap/snaptest"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/data"
+ "github.com/snapcore/snapd/integration-tests/testutils/data"
)
const snapFilenameSufix = "_1.0_all.snap"
diff -Nru snapd-2.0.5/integration-tests/testutils/cli/cli.go snapd-2.0.8/integration-tests/testutils/cli/cli.go
--- snapd-2.0.5/integration-tests/testutils/cli/cli.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/cli/cli.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,7 +28,7 @@
"path/filepath"
"strings"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/config"
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
"gopkg.in/check.v1"
)
@@ -71,11 +71,19 @@
// ExecCommandWrapper decorates the execution of the given command
func ExecCommandWrapper(cmd *exec.Cmd) (output string, err error) {
- fmt.Println(strings.Join(cmd.Args, " "))
+ cfg, err := config.ReadConfig(config.DefaultFileName)
+ if err != nil {
+ return "", err
+ }
+ if cfg.Verbose {
+ fmt.Println(strings.Join(cmd.Args, " "))
+ }
outputByte, err := cmd.CombinedOutput()
output = removeCoverageInfo(string(outputByte))
- fmt.Print(output)
- return
+ if cfg.Verbose {
+ fmt.Print(output)
+ }
+ return output, err
}
// AddOptionsToCommand inserts the required coverage options in
@@ -107,9 +115,6 @@
}
func addCoverageOptions(cmds []string, index int) ([]string, error) {
- orig := make([]string, len(cmds))
- copy(orig, cmds)
-
coveragePath := getCoveragePath()
err := os.MkdirAll(coveragePath, os.ModePerm)
if err != nil {
@@ -119,11 +124,12 @@
tmpFile := getCoverFilename()
coverprofile := filepath.Join(coveragePath, tmpFile)
- head := append(cmds[:index+1],
- []string{"-test.run=^TestRunMain$", "-test.coverprofile=" + coverprofile}...)
- tail := orig[index+1:]
+ output := append(cmds, []string{"", ""}...)
- return append(head, tail...), nil
+ copy(output[index+2:], output[index:])
+ output[index+1] = "-test.run=^TestRunMain$"
+ output[index+2] = "-test.coverprofile=" + coverprofile
+ return output, nil
}
func removeCoverageInfo(input string) string {
diff -Nru snapd-2.0.5/integration-tests/testutils/cli/cli_test.go snapd-2.0.8/integration-tests/testutils/cli/cli_test.go
--- snapd-2.0.5/integration-tests/testutils/cli/cli_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/cli/cli_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,8 +29,8 @@
"strings"
"testing"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/config"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/testutils"
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
+ "github.com/snapcore/snapd/integration-tests/testutils/testutils"
"gopkg.in/check.v1"
)
@@ -420,6 +420,61 @@
}
}
+func (s *cliTestSuite) TestAddOptionsDoesNotModifyOriginalCmds(c *check.C) {
+ for _, cmd := range s.targetCoverCmds {
+ cmdsIn := []string{cmd, "subcommand1", "subcommand2"}
+
+ _, err := AddOptionsToCommand(cmdsIn)
+
+ c.Check(err, check.IsNil)
+ c.Check(len(cmdsIn), check.Equals, 3)
+ c.Check(cmdsIn[0], check.Equals, cmd)
+ c.Check(cmdsIn[1], check.Equals, "subcommand1")
+ c.Check(cmdsIn[2], check.Equals, "subcommand2")
+ }
+}
+
+func (s *cliTestSuite) TestExecCommandWrapperDoesNotWriteVerboseOutputByDefault(c *check.C) {
+ backStdout := os.Stdout
+ defer func() { os.Stdout = backStdout }()
+ tmp, err := ioutil.TempFile("", "")
+ c.Assert(err, check.IsNil)
+ defer os.Remove(tmp.Name())
+
+ os.Stdout = tmp
+
+ _, err = ExecCommandWrapper(s.cmd)
+ c.Assert(err, check.IsNil)
+
+ completeOutput, err := ioutil.ReadFile(tmp.Name())
+ c.Assert(err, check.IsNil)
+
+ c.Assert(string(completeOutput), check.Equals, "")
+}
+
+func (s *cliTestSuite) TestExecCommandWrapperHonoursVerboseFlag(c *check.C) {
+ s.writeVerboseConfig(true)
+
+ backStdout := os.Stdout
+ defer func() { os.Stdout = backStdout }()
+ tmp, err := ioutil.TempFile("", "")
+ c.Assert(err, check.IsNil)
+ defer os.Remove(tmp.Name())
+
+ os.Stdout = tmp
+
+ cmdOutput, err := ExecCommandWrapper(s.cmd)
+ c.Assert(err, check.IsNil)
+
+ completeOutput, err := ioutil.ReadFile(tmp.Name())
+ c.Assert(err, check.IsNil)
+
+ sentCmd, err := AddOptionsToCommand(s.cmd.Args)
+
+ expected := fmt.Sprintf("%s\n%s", strings.Join(sentCmd, " "), cmdOutput)
+ c.Assert(string(completeOutput), check.Equals, expected)
+}
+
func getParamOuput(output string, cmd *exec.Cmd) string {
if len(cmd.Env) == 1 && cmd.Env[0] == defaultEnv {
output += "\nEnv variables: " + strings.Join(cmd.Env, ", ")
@@ -443,3 +498,13 @@
return nil
}
+
+func (s *cliTestSuite) writeVerboseConfig(verbose bool) {
+ testutils.PrepareTargetDir(filepath.Dir(s.configFile))
+
+ cfg := config.Config{
+ FileName: s.configFile,
+ Verbose: verbose,
+ }
+ cfg.Write()
+}
diff -Nru snapd-2.0.5/integration-tests/testutils/common/common.go snapd-2.0.8/integration-tests/testutils/common/common.go
--- snapd-2.0.5/integration-tests/testutils/common/common.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/common/common.go 2016-06-08 05:58:01.000000000 +0000
@@ -30,10 +30,10 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/config"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/partition"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
+ "github.com/snapcore/snapd/integration-tests/testutils/partition"
+ "github.com/snapcore/snapd/testutil"
)
const (
diff -Nru snapd-2.0.5/integration-tests/testutils/common/info.go snapd-2.0.8/integration-tests/testutils/common/info.go
--- snapd-2.0.5/integration-tests/testutils/common/info.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/common/info.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,7 +23,7 @@
import (
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
// dependency aliasing
diff -Nru snapd-2.0.5/integration-tests/testutils/config/config.go snapd-2.0.8/integration-tests/testutils/config/config.go
--- snapd-2.0.5/integration-tests/testutils/config/config.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/config/config.go 2016-06-08 05:58:01.000000000 +0000
@@ -38,6 +38,7 @@
Update bool
Rollback bool
FromBranch bool
+ Verbose bool
}
// Write writes the config to a file that will be copied to the test bed.
diff -Nru snapd-2.0.5/integration-tests/testutils/config/config_test.go snapd-2.0.8/integration-tests/testutils/config/config_test.go
--- snapd-2.0.5/integration-tests/testutils/config/config_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/config/config_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -46,9 +46,9 @@
func testConfigStruct(fileName string) *Config {
return &Config{
- fileName,
- "testrelease", "testchannel",
- true, true, true, true}
+ FileName: fileName,
+ Release: "testrelease", Channel: "testchannel",
+ RemoteTestbed: true, Update: true, Rollback: true, FromBranch: true, Verbose: true}
}
func testConfigContents(fileName string) string {
return `{` +
@@ -58,7 +58,8 @@
`"RemoteTestbed":true,` +
`"Update":true,` +
`"Rollback":true,` +
- `"FromBranch":true` +
+ `"FromBranch":true,` +
+ `"Verbose":true` +
`}`
}
@@ -103,14 +104,17 @@
`"RemoteTestbed":false,` +
`"Update":true,` +
`"Rollback":true,` +
- `"FromBranch":true` +
+ `"FromBranch":true,` +
+ `"Verbose":true` +
`}`
ioutil.WriteFile(configFileName, []byte(configContents), 0644)
cfg, err := ReadConfig(configFileName)
- testConfigStruct := &Config{configFileName, "testrelease", "testchannel", false, true, true, true}
+ testConfigStruct := &Config{FileName: configFileName,
+ Release: "testrelease", Channel: "testchannel",
+ RemoteTestbed: false, Update: true, Rollback: true, FromBranch: true, Verbose: true}
c.Assert(err, check.IsNil, check.Commentf("Error reading config: %v", err))
c.Assert(cfg, check.DeepEquals, testConfigStruct)
diff -Nru snapd-2.0.5/integration-tests/testutils/data/data.go snapd-2.0.8/integration-tests/testutils/data/data.go
--- snapd-2.0.5/integration-tests/testutils/data/data.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/data/data.go 2016-06-08 05:58:01.000000000 +0000
@@ -37,8 +37,12 @@
NetworkConsumerSnapName = "network-consumer"
// NetworkBindConsumerSnapName is the name of the snap with network plug
NetworkBindConsumerSnapName = "network-bind-consumer"
+ // LogObserveConsumerSnapName is the name of the snap with log-observe plug
+ LogObserveConsumerSnapName = "log-observe-consumer"
// HomeConsumerSnapName is the name of the snap with home plug
HomeConsumerSnapName = "home-consumer"
// WrongYamlSnapName is the name of a snap with an invalid meta yaml
WrongYamlSnapName = "wrong-yaml"
+ // DevKmsg reads /dev/kmsg and is useful to test confinement
+ DevKmsg = "dev-kmsg"
)
diff -Nru snapd-2.0.5/integration-tests/testutils/image/image.go snapd-2.0.8/integration-tests/testutils/image/image.go
--- snapd-2.0.5/integration-tests/testutils/image/image.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/image/image.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,7 +25,7 @@
"path/filepath"
"strings"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/testutils"
+ "github.com/snapcore/snapd/integration-tests/testutils/testutils"
)
// Image type encapsulates image actions
diff -Nru snapd-2.0.5/integration-tests/testutils/refresh/refresh.go snapd-2.0.8/integration-tests/testutils/refresh/refresh.go
--- snapd-2.0.5/integration-tests/testutils/refresh/refresh.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/refresh/refresh.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,120 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+// +build !excludeintegration
+
+/*
+ * Copyright (C) 2015, 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package refresh
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/store"
+)
+
+// ChangeFakeUpdateSnap is the type of the functions used to modify a snap before it is served as
+// a fake update.
+type ChangeFakeUpdateSnap func(snapPath string) error
+
+// NoOp leaves the snap unchanged.
+func NoOp(snapPath string) error {
+ return nil
+}
+
+// CallFakeSnapRefresh calls snappy update after faking a new version available for the specified snap.
+// The fake is made copying the currently installed snap.
+// changeFunc can be used to modify the snap before it is built and served.
+func CallFakeSnapRefreshForSnap(c *check.C, snap string, changeFunc ChangeFakeUpdateSnap, fakeStore *store.Store) string {
+ c.Log("Preparing fake single snap and calling update.")
+
+ blobDir := fakeStore.SnapsDir()
+ MakeFakeRefreshForSnap(c, snap, blobDir, changeFunc)
+
+ cli.ExecCommand(c, "sudo", "snap", "refresh", snap)
+
+ // FIXME: do we want an automatic `snap list` output after
+ // `snap update` (like in the old snappy world)?
+ return cli.ExecCommand(c, "snap", "list")
+}
+
+func CallFakeSnapRefreshAll(c *check.C, snaps []string, changeFunc ChangeFakeUpdateSnap, fakeStore *store.Store) string {
+ c.Log("Preparing fake and calling update.")
+
+ blobDir := fakeStore.SnapsDir()
+ for _, snap := range snaps {
+ MakeFakeRefreshForSnap(c, snap, blobDir, changeFunc)
+ }
+
+ return cli.ExecCommand(c, "sudo", "snap", "refresh")
+}
+
+func MakeFakeRefreshForSnap(c *check.C, snap, targetDir string, changeFunc ChangeFakeUpdateSnap) error {
+
+ // make a fake update snap in /var/tmp (which is not a tempfs)
+ fakeUpdateDir, err := ioutil.TempDir("/var/tmp", "snap-build-")
+ c.Assert(err, check.IsNil)
+ // ensure the "." of the squashfs has sane owner/permissions
+ cli.ExecCommand(c, "sudo", "chown", "root:root", fakeUpdateDir)
+ cli.ExecCommand(c, "sudo", "chmod", "0755", fakeUpdateDir)
+ defer cli.ExecCommand(c, "sudo", "rm", "-rf", fakeUpdateDir)
+
+ copySnap(c, snap, fakeUpdateDir)
+
+ // fake new version
+ cli.ExecCommand(c, "sudo", "sed", "-i", `s/version:\(.*\)/version:\1+fake1/`, filepath.Join(fakeUpdateDir, "meta/snap.yaml"))
+
+ if err := changeFunc(fakeUpdateDir); err != nil {
+ return err
+ }
+ buildSnap(c, fakeUpdateDir, targetDir)
+ return nil
+}
+
+func copySnap(c *check.C, snap, targetDir string) {
+ // check for sideloaded snaps
+ // XXX: simplify this down to consider only the name (and not origin)
+ // in the directory once everything is moved to that
+ baseDir := filepath.Join(dirs.SnapSnapsDir, snap)
+ if _, err := os.Stat(baseDir); os.IsNotExist(err) {
+ snapName := strings.Split(snap, ".")[0]
+ baseDir = filepath.Join(dirs.SnapSnapsDir, snapName)
+ if _, err := os.Stat(baseDir); os.IsNotExist(err) {
+ baseDir = filepath.Join(dirs.SnapSnapsDir, snapName+".sideload")
+ _, err = os.Stat(baseDir)
+ c.Assert(err, check.IsNil,
+ check.Commentf("%s not found from it's original source not sideloaded", snap))
+ }
+ }
+ sourceDir := filepath.Join(baseDir, "current")
+ files, err := filepath.Glob(filepath.Join(sourceDir, "*"))
+ c.Assert(err, check.IsNil)
+ for _, m := range files {
+ cli.ExecCommand(c, "sudo", "cp", "-a", m, targetDir)
+ }
+}
+
+func buildSnap(c *check.C, snapDir, targetDir string) {
+ // build in /var/tmp (which is not a tempfs)
+ cli.ExecCommand(c, "sudo", "TMPDIR=/var/tmp", "snapbuild", snapDir, targetDir)
+}
diff -Nru snapd-2.0.5/integration-tests/testutils/report/parser.go snapd-2.0.8/integration-tests/testutils/report/parser.go
--- snapd-2.0.5/integration-tests/testutils/report/parser.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/report/parser.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,7 +28,7 @@
"github.com/testing-cabal/subunit-go"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
)
const (
diff -Nru snapd-2.0.5/integration-tests/testutils/report/parser_test.go snapd-2.0.8/integration-tests/testutils/report/parser_test.go
--- snapd-2.0.5/integration-tests/testutils/report/parser_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/report/parser_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -30,7 +30,7 @@
"github.com/testing-cabal/subunit-go"
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
+ "github.com/snapcore/snapd/integration-tests/testutils/common"
)
var _ = check.Suite(&ParserReportSuite{})
@@ -85,12 +85,12 @@
"testSuite.TestExists",
"exists",
}, {
- "PASS: /tmp/snappy-tests-job/18811/src/github.com/ubuntu-core/snappy/integration-tests/tests/" +
+ "PASS: /tmp/snappy-tests-job/18811/src/github.com/snapcore/snapd/integration-tests/tests/" +
"apt_test.go:34: testSuite.TestSuccess 0.005s\n",
"testSuite.TestSuccess",
"success",
}, {
- "FAIL: /tmp/snappy-tests-job/710/src/github.com/ubuntu-core/snappy/integration-tests/tests/" +
+ "FAIL: /tmp/snappy-tests-job/710/src/github.com/snapcore/snapd/integration-tests/tests/" +
"installFramework_test.go:85: testSuite.TestFail\n",
"testSuite.TestFail",
"fail",
@@ -112,7 +112,7 @@
testID := "testSuite.TestSkip"
skipReason := "skip reason"
s.subject.Write([]byte(
- fmt.Sprintf("SKIP: /tmp/snappy-tests-job/21647/src/github.com/ubuntu-core/snappy/"+
+ fmt.Sprintf("SKIP: /tmp/snappy-tests-job/21647/src/github.com/snapcore/snapd/"+
"integration-tests/tests/info_test.go:36: %s (%s)\n", testID, skipReason)))
c.Check(s.spy.calls, check.HasLen, 1)
@@ -210,7 +210,7 @@
testID := "testSuite.SetUpTest"
skipReason := "skip reason"
s.subject.Write([]byte(
- fmt.Sprintf("SKIP: /tmp/snappy-tests-job/21647/src/github.com/ubuntu-core/snappy/"+
+ fmt.Sprintf("SKIP: /tmp/snappy-tests-job/21647/src/github.com/snapcore/snapd/"+
"integration-tests/tests/info_test.go:36: %s (%s)\n", testID, skipReason)))
c.Check(s.spy.calls, check.HasLen, 0)
diff -Nru snapd-2.0.5/integration-tests/testutils/store/store.go snapd-2.0.8/integration-tests/testutils/store/store.go
--- snapd-2.0.5/integration-tests/testutils/store/store.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/store/store.go 2016-06-08 05:58:01.000000000 +0000
@@ -31,7 +31,7 @@
"gopkg.in/tylerb/graceful.v1"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
var (
@@ -80,7 +80,7 @@
mux.HandleFunc("/", rootEndpoint)
mux.HandleFunc("/search", store.searchEndpoint)
mux.HandleFunc("/package/", store.detailsEndpoint)
- mux.HandleFunc("/click-metadata", store.bulkEndpoint)
+ mux.HandleFunc("/metadata", store.bulkEndpoint)
mux.Handle("/download/", http.StripPrefix("/download/", http.FileServer(http.Dir(blobDir))))
return store
@@ -147,6 +147,7 @@
type detailsReplyJSON struct {
Name string `json:"name"`
+ SnapID string `json:"snap_id"`
PackageName string `json:"package_name"`
Developer string `json:"origin"`
AnonDownloadURL string `json:"anon_download_url"`
@@ -247,23 +248,36 @@
return nil
}
+type candidateSnap struct {
+ SnapID string `json:"snap_id"`
+}
+
type bulkReqJSON struct {
- Name []string
+ CandidateSnaps []candidateSnap `json:"snaps"`
+ Fields []string `json:"fields"`
+}
+
+type payload struct {
+ Packages []detailsReplyJSON `json:"clickindex:package"`
}
type bulkReplyJSON struct {
- Status string `json:"status"`
- Name string `json:"name"`
- PackageName string `json:"package_name"`
- Developer string `json:"origin"`
- AnonDownloadURL string `json:"anon_download_url"`
- Version string `json:"version"`
- Revision int `json:"revision"`
+ Payload payload `json:"_embedded"`
+}
+
+// FIXME: find a better way to extract the snapID -> name mapping
+// for the fake store
+var snapIDtoName = map[string]string{
+ "buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ": "hello-world",
+ "EQPfyVOJF0AZNz9P2IJ6UKwldLFN5TzS": "xkcd-webserver",
+ "b8X2psL1ryVrPt5WEmpYiqfr5emixTd7": "ubuntu-core",
+ "bul8uZn9U3Ll4ke6BMqvNVEZjuJCSQvO": "canonical-pc",
+ "SkKeDk2PRgBrX89DdgULk3pyY5DJo6Jk": "canonical-pc-linux",
}
func (s *Store) bulkEndpoint(w http.ResponseWriter, req *http.Request) {
var pkgs bulkReqJSON
- var replyData []bulkReplyJSON
+ var replyData bulkReplyJSON
decoder := json.NewDecoder(req.Body)
if err := decoder.Decode(&pkgs); err != nil {
@@ -273,11 +287,16 @@
s.refreshSnaps()
- // check if we have downloadable snap of the given name
- for _, pkgWithChannel := range pkgs.Name {
- pkg := strings.Split(pkgWithChannel, "/")[0]
+ // check if we have downloadable snap of the given SnapID
+ for _, pkg := range pkgs.CandidateSnaps {
+
+ name := snapIDtoName[pkg.SnapID]
+ if name == "" {
+ http.Error(w, fmt.Sprintf("unknown snapid: %q", pkg.SnapID), http.StatusBadRequest)
+ return
+ }
- if fn, ok := s.snaps[pkg]; ok {
+ if fn, ok := s.snaps[name]; ok {
snapFile, err := snap.Open(fn)
if err != nil {
http.Error(w, fmt.Sprintf("can not read: %v: %v", fn, err), http.StatusBadRequest)
@@ -291,11 +310,12 @@
return
}
- replyData = append(replyData, bulkReplyJSON{
- Status: "Published",
+ replyData.Payload.Packages = append(replyData.Payload.Packages, detailsReplyJSON{
Name: fmt.Sprintf("%s.%s", info.Name(), s.defaultDeveloper),
+ SnapID: pkg.SnapID,
PackageName: info.Name(),
Developer: defaultDeveloper,
+ DownloadURL: fmt.Sprintf("%s/download/%s", s.URL(), filepath.Base(fn)),
AnonDownloadURL: fmt.Sprintf("%s/download/%s", s.URL(), filepath.Base(fn)),
Version: info.Version,
Revision: makeRevision(info),
@@ -311,4 +331,5 @@
return
}
w.Write(out)
+
}
diff -Nru snapd-2.0.5/integration-tests/testutils/store/store_test.go snapd-2.0.8/integration-tests/testutils/store/store_test.go
--- snapd-2.0.5/integration-tests/testutils/store/store_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/store/store_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,8 +29,8 @@
"path/filepath"
"testing"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap/snaptest"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap/snaptest"
. "gopkg.in/check.v1"
)
@@ -114,6 +114,7 @@
"clickindex:package": [
{
"name": "foo.canonical",
+ "snap_id": "",
"package_name": "foo",
"origin": "canonical",
"anon_download_url": "%s/download/foo_1_all.snap",
@@ -127,11 +128,11 @@
}
func (s *storeTestSuite) TestBulkEndpoint(c *C) {
- c.Skip("not relevant atm, will change")
- s.makeTestSnap(c, "name: foo\nversion: 1")
+ s.makeTestSnap(c, "name: hello-world\nversion: 1")
- resp, err := s.StorePostJSON("/click-metadata", []byte(`{
-"name": ["foo.canonical"]
+ // note that we send the hello-world snapID here
+ resp, err := s.StorePostJSON("/metadata", []byte(`{
+"snaps": [{"snap_id":"buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ","channel":"stable","revision":1}]
}`))
c.Assert(err, IsNil)
defer resp.Body.Close()
@@ -139,17 +140,22 @@
c.Assert(resp.StatusCode, Equals, 200)
body, err := ioutil.ReadAll(resp.Body)
c.Assert(err, IsNil)
- c.Assert(string(body), Equals, fmt.Sprintf(`[
- {
- "status": "Published",
- "name": "foo.canonical",
- "package_name": "foo",
- "origin": "canonical",
- "anon_download_url": "%s/download/foo_1_all.snap",
- "version": "1",
- "revision": 424242
+ c.Assert(string(body), Equals, fmt.Sprintf(`{
+ "_embedded": {
+ "clickindex:package": [
+ {
+ "name": "hello-world.canonical",
+ "snap_id": "buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ",
+ "package_name": "hello-world",
+ "origin": "canonical",
+ "anon_download_url": "%[1]s/download/hello-world_1_all.snap",
+ "download_url": "%[1]s/download/hello-world_1_all.snap",
+ "version": "1",
+ "revision": 424242
+ }
+ ]
}
-]`, s.store.URL()))
+}`, s.store.URL()))
}
// FIXME: extract into snappy/testutils
diff -Nru snapd-2.0.5/integration-tests/testutils/testutils/testutils.go snapd-2.0.8/integration-tests/testutils/testutils/testutils.go
--- snapd-2.0.5/integration-tests/testutils/testutils/testutils.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/testutils/testutils.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,6 +26,8 @@
"os"
"os/exec"
"strings"
+
+ "github.com/snapcore/snapd/integration-tests/testutils/config"
)
// PrepareTargetDir creates the given target directory, removing it previously if it didn't exist
@@ -48,13 +50,18 @@
// ExecCommand executes the given command and pipes the results to os.Stdout and os.Stderr, returning the resulting error
func ExecCommand(cmds ...string) error {
- fmt.Println(strings.Join(cmds, " "))
-
+ cfg, err := config.ReadConfig(config.DefaultFileName)
+ if err != nil {
+ return err
+ }
+ if cfg.Verbose {
+ fmt.Println(strings.Join(cmds, " "))
+ }
cmd := exec.Command(cmds[0], cmds[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
- err := cmd.Run()
+ err = cmd.Run()
if err != nil {
log.Panicf("Error while running %s: %s\n", cmd.Args, err)
}
diff -Nru snapd-2.0.5/integration-tests/testutils/updates/updates.go snapd-2.0.8/integration-tests/testutils/updates/updates.go
--- snapd-2.0.5/integration-tests/testutils/updates/updates.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/updates/updates.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,140 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-// +build !excludeintegration
-
-/*
- * Copyright (C) 2015, 2016 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package updates
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-
- "gopkg.in/check.v1"
-
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/common"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/partition"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/store"
-)
-
-// ChangeFakeUpdateSnap is the type of the functions used to modify a snap before it is served as
-// a fake update.
-type ChangeFakeUpdateSnap func(snapPath string) error
-
-// NoOp leaves the snap unchanged.
-func NoOp(snapPath string) error {
- return nil
-}
-
-// CallFakeSnapRefresh calls snappy update after faking a new version available for the specified snap.
-// The fake is made copying the currently installed snap.
-// changeFunc can be used to modify the snap before it is built and served.
-func CallFakeSnapRefresh(c *check.C, snap string, changeFunc ChangeFakeUpdateSnap, fakeStore *store.Store) string {
- c.Log("Preparing fake and calling update.")
-
- blobDir := fakeStore.SnapsDir()
- makeFakeUpdateForSnap(c, snap, blobDir, changeFunc)
-
- // FIMXE: there is no "snap refresh" that updates all snaps
- cli.ExecCommand(c, "sudo", "snap", "refresh", snap)
-
- // FIXME: do we want an automatic `snap list` output after
- // `snap update` (like in the old snappy world)?
- return cli.ExecCommand(c, "snap", "list")
-}
-
-// FIXME: remove once "snappy" the command is gone
-func CallFakeUpdate(c *check.C, snap string, changeFunc ChangeFakeUpdateSnap) string {
- c.Log("Preparing fake and calling update.")
-
- // use /var/tmp is not a tempfs
- blobDir, err := ioutil.TempDir("/var/tmp", "snap-fake-store-blobs-")
- c.Assert(err, check.IsNil)
- defer cli.ExecCommand(c, "sudo", "rm", "-rf", blobDir)
-
- fakeStore := store.NewStore(blobDir)
- err = fakeStore.Start()
- c.Assert(err, check.IsNil)
- defer fakeStore.Stop()
-
- makeFakeUpdateForSnap(c, snap, blobDir, changeFunc)
-
- return cli.ExecCommand(c, "sudo", "TMPDIR=/var/tmp", fmt.Sprintf("SNAPPY_FORCE_CPI_URL=%s", fakeStore.URL()), "snap", "refresh", snap)
-}
-
-// CallFakeOSUpdate calls snappy update after faking a new version available for the OS snap.
-func CallFakeOSUpdate(c *check.C) string {
- currentVersion := common.GetCurrentUbuntuCoreVersion(c)
- common.SetSavedVersion(c, currentVersion)
-
- return CallFakeUpdate(c, partition.OSSnapName(c)+".canonical", NoOp)
-}
-
-func makeFakeUpdateForSnap(c *check.C, snap, targetDir string, changeFunc ChangeFakeUpdateSnap) error {
-
- // make a fake update snap in /var/tmp (which is not a tempfs)
- fakeUpdateDir, err := ioutil.TempDir("/var/tmp", "snap-build-")
- c.Assert(err, check.IsNil)
- // ensure the "." of the squashfs has sane owner/permissions
- cli.ExecCommand(c, "sudo", "chown", "root:root", fakeUpdateDir)
- cli.ExecCommand(c, "sudo", "chmod", "0755", fakeUpdateDir)
- defer cli.ExecCommand(c, "sudo", "rm", "-rf", fakeUpdateDir)
-
- copySnap(c, snap, fakeUpdateDir)
-
- // fake new version
- cli.ExecCommand(c, "sudo", "sed", "-i", `s/version:\(.*\)/version:\1+fake1/`, filepath.Join(fakeUpdateDir, "meta/snap.yaml"))
-
- if err := changeFunc(fakeUpdateDir); err != nil {
- return err
- }
- buildSnap(c, fakeUpdateDir, targetDir)
- return nil
-}
-
-func copySnap(c *check.C, snap, targetDir string) {
- // check for sideloaded snaps
- // XXX: simplify this down to consider only the name (and not origin)
- // in the directory once everything is moved to that
- baseDir := filepath.Join(dirs.SnapSnapsDir, snap)
- if _, err := os.Stat(baseDir); os.IsNotExist(err) {
- snapName := strings.Split(snap, ".")[0]
- baseDir = filepath.Join(dirs.SnapSnapsDir, snapName)
- if _, err := os.Stat(baseDir); os.IsNotExist(err) {
- baseDir = filepath.Join(dirs.SnapSnapsDir, snapName+".sideload")
- _, err = os.Stat(baseDir)
- c.Assert(err, check.IsNil,
- check.Commentf("%s not found from it's original source not sideloaded", snap))
- }
- }
- sourceDir := filepath.Join(baseDir, "current")
- files, err := filepath.Glob(filepath.Join(sourceDir, "*"))
- c.Assert(err, check.IsNil)
- for _, m := range files {
- cli.ExecCommand(c, "sudo", "cp", "-a", m, targetDir)
- }
-}
-
-func buildSnap(c *check.C, snapDir, targetDir string) {
- // build in /var/tmp (which is not a tempfs)
- cli.ExecCommand(c, "sudo", "TMPDIR=/var/tmp", "snapbuild", snapDir, targetDir)
-}
diff -Nru snapd-2.0.5/integration-tests/testutils/wait/wait.go snapd-2.0.8/integration-tests/testutils/wait/wait.go
--- snapd-2.0.5/integration-tests/testutils/wait/wait.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/integration-tests/testutils/wait/wait.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/integration-tests/testutils/cli"
+ "github.com/snapcore/snapd/integration-tests/testutils/cli"
)
var (
diff -Nru snapd-2.0.5/interfaces/apparmor/apparmor.go snapd-2.0.8/interfaces/apparmor/apparmor.go
--- snapd-2.0.5/interfaces/apparmor/apparmor.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/apparmor/apparmor.go 2016-06-08 05:58:01.000000000 +0000
@@ -33,7 +33,7 @@
"path/filepath"
"strings"
- "github.com/ubuntu-core/snappy/dirs"
+ "github.com/snapcore/snapd/dirs"
)
// LoadProfile loads an apparmor profile from the given file.
diff -Nru snapd-2.0.5/interfaces/apparmor/apparmor_test.go snapd-2.0.8/interfaces/apparmor/apparmor_test.go
--- snapd-2.0.5/interfaces/apparmor/apparmor_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/apparmor/apparmor_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,9 +28,9 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces/apparmor"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces/apparmor"
+ "github.com/snapcore/snapd/testutil"
)
func Test(t *testing.T) {
diff -Nru snapd-2.0.5/interfaces/apparmor/backend.go snapd-2.0.8/interfaces/apparmor/backend.go
--- snapd-2.0.5/interfaces/apparmor/backend.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/apparmor/backend.go 2016-06-08 05:58:01.000000000 +0000
@@ -45,10 +45,10 @@
"regexp"
"sort"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
)
// Backend is responsible for maintaining apparmor profiles for ubuntu-core-launcher.
diff -Nru snapd-2.0.5/interfaces/apparmor/backend_test.go snapd-2.0.8/interfaces/apparmor/backend_test.go
--- snapd-2.0.5/interfaces/apparmor/backend_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/apparmor/backend_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,11 +27,11 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/apparmor"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/apparmor"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
)
type backendSuite struct {
@@ -318,7 +318,7 @@
func (s *backendSuite) installSnap(c *C, devMode bool, snapYaml string, revision int) *snap.Info {
snapInfo, err := snap.InfoFromSnapYaml([]byte(snapYaml))
c.Assert(err, IsNil)
- snapInfo.Revision = revision
+ snapInfo.Revision = snap.R(revision)
// this won't come from snap.yaml
snapInfo.Developer = "acme"
err = s.repo.AddSnap(snapInfo)
@@ -332,7 +332,7 @@
func (s *backendSuite) updateSnap(c *C, oldSnapInfo *snap.Info, devMode bool, snapYaml string, revision int) *snap.Info {
newSnapInfo, err := snap.InfoFromSnapYaml([]byte(snapYaml))
c.Assert(err, IsNil)
- newSnapInfo.Revision = revision
+ newSnapInfo.Revision = snap.R(revision)
// this won't come from snap.yaml
newSnapInfo.Developer = "acme"
c.Assert(newSnapInfo.Name(), Equals, oldSnapInfo.Name())
diff -Nru snapd-2.0.5/interfaces/apparmor/export_test.go snapd-2.0.8/interfaces/apparmor/export_test.go
--- snapd-2.0.5/interfaces/apparmor/export_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/apparmor/export_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package apparmor
import (
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/testutil"
)
// MockProfilesPath mocks the file read by LoadedProfiles()
diff -Nru snapd-2.0.5/interfaces/apparmor/template.go snapd-2.0.8/interfaces/apparmor/template.go
--- snapd-2.0.5/interfaces/apparmor/template.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/apparmor/template.go 2016-06-08 05:58:01.000000000 +0000
@@ -216,6 +216,18 @@
@{PROC}/sys/kernel/pid_max r,
@{PROC}/sys/kernel/random/uuid r,
+ # Reads of oom_adj and oom_score_adj are safe
+ owner @{PROC}/@{pid}/oom_{,score_}adj r,
+
+ # Note: for now, don't explicitly deny write access so --devmode isn't broken
+ # but eventually we may conditionally deny this since it allows the process
+ # to increase the oom heuristic of other processes (make them more likely to
+ # be killed). Once AppArmor kernel var is available to solve this properly,
+ # this can safely be allowed since non-root processes won't be able to
+ # decrease the value and root processes will only be able to with
+ # 'capability sys_resource,' which we deny be default.
+ # deny owner @{PROC}/@{pid}/oom_{,score_}adj w,
+
# Eases hardware assignment (doesn't give anything away)
/etc/udev/udev.conf r,
/sys/ r,
diff -Nru snapd-2.0.5/interfaces/apparmor/template_vars.go snapd-2.0.8/interfaces/apparmor/template_vars.go
--- snapd-2.0.5/interfaces/apparmor/template_vars.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/apparmor/template_vars.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,7 +23,7 @@
"bytes"
"fmt"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
// templateVariables returns text defining apparmor variables that can be used in the
@@ -32,7 +32,7 @@
var buf bytes.Buffer
fmt.Fprintf(&buf, "@{APP_NAME}=\"%s\"\n", appInfo.Name)
fmt.Fprintf(&buf, "@{SNAP_NAME}=\"%s\"\n", appInfo.Snap.Name())
- fmt.Fprintf(&buf, "@{SNAP_REVISION}=\"%d\"\n", appInfo.Snap.Revision)
+ fmt.Fprintf(&buf, "@{SNAP_REVISION}=\"%s\"\n", appInfo.Snap.Revision)
fmt.Fprintf(&buf, "@{INSTALL_DIR}=\"/snap\"")
return buf.Bytes()
}
diff -Nru snapd-2.0.5/interfaces/backend.go snapd-2.0.8/interfaces/backend.go
--- snapd-2.0.5/interfaces/backend.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/backend.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package interfaces
import (
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
// SecurityBackend abstracts interactions between the interface system and the
diff -Nru snapd-2.0.5/interfaces/builtin/all.go snapd-2.0.8/interfaces/builtin/all.go
--- snapd-2.0.5/interfaces/builtin/all.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/all.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,14 +20,17 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
var allInterfaces = []interfaces.Interface{
&BoolFileInterface{},
&BluezInterface{},
+ &LocationControlInterface{},
+ &LocationObserveInterface{},
&NetworkManagerInterface{},
NewFirewallControlInterface(),
+ NewGsettingsInterface(),
NewHomeInterface(),
NewLocaleControlInterface(),
NewLogObserveInterface(),
@@ -43,6 +46,8 @@
NewUnity7Interface(),
NewX11Interface(),
NewOpenglInterface(),
+ NewPulseAudioInterface(),
+ NewCupsControlInterface(),
}
// Interfaces returns all of the built-in interfaces.
diff -Nru snapd-2.0.5/interfaces/builtin/all_test.go snapd-2.0.8/interfaces/builtin/all_test.go
--- snapd-2.0.5/interfaces/builtin/all_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/all_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,8 +20,8 @@
package builtin_test
import (
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- . "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ . "github.com/snapcore/snapd/testutil"
. "gopkg.in/check.v1"
)
@@ -34,7 +34,10 @@
all := builtin.Interfaces()
c.Check(all, Contains, &builtin.BoolFileInterface{})
c.Check(all, Contains, &builtin.BluezInterface{})
+ c.Check(all, Contains, &builtin.LocationControlInterface{})
+ c.Check(all, Contains, &builtin.LocationObserveInterface{})
c.Check(all, DeepContains, builtin.NewFirewallControlInterface())
+ c.Check(all, DeepContains, builtin.NewGsettingsInterface())
c.Check(all, DeepContains, builtin.NewHomeInterface())
c.Check(all, DeepContains, builtin.NewLocaleControlInterface())
c.Check(all, DeepContains, builtin.NewLogObserveInterface())
@@ -50,4 +53,6 @@
c.Check(all, DeepContains, builtin.NewUnity7Interface())
c.Check(all, DeepContains, builtin.NewX11Interface())
c.Check(all, DeepContains, builtin.NewOpenglInterface())
+ c.Check(all, DeepContains, builtin.NewPulseAudioInterface())
+ c.Check(all, DeepContains, builtin.NewCupsControlInterface())
}
diff -Nru snapd-2.0.5/interfaces/builtin/bluez.go snapd-2.0.8/interfaces/builtin/bluez.go
--- snapd-2.0.5/interfaces/builtin/bluez.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/bluez.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"bytes"
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
var bluezPermanentSlotAppArmor = []byte(`
diff -Nru snapd-2.0.5/interfaces/builtin/bluez_test.go snapd-2.0.8/interfaces/builtin/bluez_test.go
--- snapd-2.0.5/interfaces/builtin/bluez_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/bluez_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,10 +22,10 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
)
type BluezInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/bool_file.go snapd-2.0.8/interfaces/builtin/bool_file.go
--- snapd-2.0.5/interfaces/builtin/bool_file.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/bool_file.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
"path/filepath"
"regexp"
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// BoolFileInterface is the type of all the bool-file interfaces.
diff -Nru snapd-2.0.5/interfaces/builtin/bool_file_test.go snapd-2.0.8/interfaces/builtin/bool_file_test.go
--- snapd-2.0.5/interfaces/builtin/bool_file_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/bool_file_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,10 +26,10 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
)
func Test(t *testing.T) {
diff -Nru snapd-2.0.5/interfaces/builtin/common.go snapd-2.0.8/interfaces/builtin/common.go
--- snapd-2.0.5/interfaces/builtin/common.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/common.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,8 +23,8 @@
"fmt"
"path/filepath"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/snap"
)
type evalSymlinksFn func(string) (string, error)
diff -Nru snapd-2.0.5/interfaces/builtin/common_test.go snapd-2.0.8/interfaces/builtin/common_test.go
--- snapd-2.0.5/interfaces/builtin/common_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/common_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/testutil"
)
// MockEvalSymlinks replaces the path/filepath.EvalSymlinks function used inside the caps package.
diff -Nru snapd-2.0.5/interfaces/builtin/cups_control.go snapd-2.0.8/interfaces/builtin/cups_control.go
--- snapd-2.0.5/interfaces/builtin/cups_control.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/cups_control.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,44 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package builtin
+
+import "github.com/snapcore/snapd/interfaces"
+
+const cupsControlConnectedPlugAppArmor = `
+# Description: Can access cups control socket. This is restricted because it provides
+# privileged access to configure printing.
+
+#include
+`
+
+const cupsControlConnectedPlugSecComp = `
+setsockopt
+`
+
+// NewCupsControlInterface returns a new "cups" interface.
+func NewCupsControlInterface() interfaces.Interface {
+ return &commonInterface{
+ name: "cups-control",
+ connectedPlugAppArmor: cupsControlConnectedPlugAppArmor,
+ connectedPlugSecComp: cupsControlConnectedPlugSecComp,
+ reservedForOS: true,
+ autoConnect: false,
+ }
+}
diff -Nru snapd-2.0.5/interfaces/builtin/firewall_control.go snapd-2.0.8/interfaces/builtin/firewall_control.go
--- snapd-2.0.5/interfaces/builtin/firewall_control.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/firewall_control.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/firewall-control
@@ -51,6 +51,7 @@
# snappy needs to have iptable_filter and ip6table_filter loaded,
# they don't autoload.
unix (bind) type=stream addr="@xtables",
+/{,var/}run/xtables.lock rwk,
@{PROC}/sys/kernel/modprobe r,
@{PROC}/@{pid}/net/ r,
diff -Nru snapd-2.0.5/interfaces/builtin/firewall_control_test.go snapd-2.0.8/interfaces/builtin/firewall_control_test.go
--- snapd-2.0.5/interfaces/builtin/firewall_control_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/firewall_control_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type FirewallControlInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/gsettings.go snapd-2.0.8/interfaces/builtin/gsettings.go
--- snapd-2.0.5/interfaces/builtin/gsettings.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/gsettings.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,67 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package builtin
+
+import (
+ "github.com/snapcore/snapd/interfaces"
+)
+
+const gsettingsConnectedPlugAppArmor = `
+# Description: Can access global gsettings of the user's session. Restricted
+# because this gives privileged access to sensitive information stored in
+# gsettings and allows adjusting settings of other applications.
+# Usage: reserved
+
+#include
+
+#include
+owner /{,var/}run/user/*/dconf/user w,
+owner @{HOME}/.config/dconf/user w,
+dbus (receive, send)
+ bus=session
+ interface="ca.desrt.dconf.Writer"
+ peer=(label=unconfined),
+`
+
+const gsettingsConnectedPlugSecComp = `
+# Description: Can access global gsettings of the user's session. Restricted
+# because this gives privileged access to sensitive information stored in
+# gsettings and allows adjusting settings of other applications.
+
+# dbus
+connect
+getsockname
+recvmsg
+send
+sendto
+sendmsg
+socket
+`
+
+// NewGsettingsInterface returns a new "gsettings" interface.
+func NewGsettingsInterface() interfaces.Interface {
+ return &commonInterface{
+ name: "gsettings",
+ connectedPlugAppArmor: gsettingsConnectedPlugAppArmor,
+ connectedPlugSecComp: gsettingsConnectedPlugSecComp,
+ reservedForOS: true,
+ autoConnect: true,
+ }
+}
diff -Nru snapd-2.0.5/interfaces/builtin/gsettings_test.go snapd-2.0.8/interfaces/builtin/gsettings_test.go
--- snapd-2.0.5/interfaces/builtin/gsettings_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/gsettings_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,132 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package builtin_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+)
+
+type GsettingsInterfaceSuite struct {
+ iface interfaces.Interface
+ slot *interfaces.Slot
+ plug *interfaces.Plug
+}
+
+var _ = Suite(&GsettingsInterfaceSuite{
+ iface: builtin.NewGsettingsInterface(),
+ slot: &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "ubuntu-core", Type: snap.TypeOS},
+ Name: "gsettings",
+ Interface: "gsettings",
+ },
+ },
+ plug: &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{SuggestedName: "other"},
+ Name: "gsettings",
+ Interface: "gsettings",
+ },
+ },
+})
+
+func (s *GsettingsInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "gsettings")
+}
+
+func (s *GsettingsInterfaceSuite) TestSanitizeSlot(c *C) {
+ err := s.iface.SanitizeSlot(s.slot)
+ c.Assert(err, IsNil)
+ err = s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "some-snap"},
+ Name: "gsettings",
+ Interface: "gsettings",
+ }})
+ c.Assert(err, ErrorMatches, "gsettings slots are reserved for the operating system snap")
+}
+
+func (s *GsettingsInterfaceSuite) TestSanitizePlug(c *C) {
+ err := s.iface.SanitizePlug(s.plug)
+ c.Assert(err, IsNil)
+}
+
+func (s *GsettingsInterfaceSuite) TestSanitizeIncorrectInterface(c *C) {
+ c.Assert(func() { s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{Interface: "other"}}) },
+ PanicMatches, `slot is not of interface "gsettings"`)
+ c.Assert(func() { s.iface.SanitizePlug(&interfaces.Plug{PlugInfo: &snap.PlugInfo{Interface: "other"}}) },
+ PanicMatches, `plug is not of interface "gsettings"`)
+}
+
+func (s *GsettingsInterfaceSuite) TestUnusedSecuritySystems(c *C) {
+ systems := [...]interfaces.SecuritySystem{interfaces.SecurityAppArmor,
+ interfaces.SecuritySecComp, interfaces.SecurityDBus,
+ interfaces.SecurityUDev}
+ for _, system := range systems {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityDBus)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityUDev)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+}
+
+func (s *GsettingsInterfaceSuite) TestUsedSecuritySystems(c *C) {
+ // connected plugs have a non-nil security snippet for apparmor
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ // connected plugs have a non-nil security snippet for seccomp
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecuritySecComp)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+}
+
+func (s *GsettingsInterfaceSuite) TestUnexpectedSecuritySystems(c *C) {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+}
+
+func (s *GsettingsInterfaceSuite) TestAutoConnect(c *C) {
+ c.Check(s.iface.AutoConnect(), Equals, true)
+}
diff -Nru snapd-2.0.5/interfaces/builtin/home.go snapd-2.0.8/interfaces/builtin/home.go
--- snapd-2.0.5/interfaces/builtin/home.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/home.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/home
@@ -49,5 +49,6 @@
name: "home",
connectedPlugAppArmor: homeConnectedPlugAppArmor,
reservedForOS: true,
+ autoConnect: true,
}
}
diff -Nru snapd-2.0.5/interfaces/builtin/home_test.go snapd-2.0.8/interfaces/builtin/home_test.go
--- snapd-2.0.5/interfaces/builtin/home_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/home_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type HomeInterfaceSuite struct {
@@ -124,5 +124,5 @@
}
func (s *HomeInterfaceSuite) TestAutoConnect(c *C) {
- c.Check(s.iface.AutoConnect(), Equals, false)
+ c.Check(s.iface.AutoConnect(), Equals, true)
}
diff -Nru snapd-2.0.5/interfaces/builtin/locale_control.go snapd-2.0.8/interfaces/builtin/locale_control.go
--- snapd-2.0.5/interfaces/builtin/locale_control.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/locale_control.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/locale-control
diff -Nru snapd-2.0.5/interfaces/builtin/locale_control_test.go snapd-2.0.8/interfaces/builtin/locale_control_test.go
--- snapd-2.0.5/interfaces/builtin/locale_control_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/locale_control_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type LocaleControlInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/location_control.go snapd-2.0.8/interfaces/builtin/location_control.go
--- snapd-2.0.5/interfaces/builtin/location_control.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/location_control.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,211 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package builtin
+
+import (
+ "bytes"
+
+ "github.com/snapcore/snapd/interfaces"
+)
+
+var locationControlPermanentSlotAppArmor = []byte(`
+# Description: Allow operating as the location service. Reserved because this
+# gives privileged access to the system.
+# Usage: reserved
+
+# DBus accesses
+#include
+dbus (send)
+ bus=system
+ path=/org/freedesktop/DBus
+ interface=org.freedesktop.DBus
+ member="{Request,Release}Name"
+ peer=(name=org.freedesktop.DBus, label=unconfined),
+
+dbus (send)
+ bus=system
+ path=/org/freedesktop/DBus
+ interface=org.freedesktop.DBus
+ member="GetConnectionUnix{ProcessID,User}"
+ peer=(label=unconfined),
+
+# Allow binding the service to the requested connection name
+dbus (bind)
+ bus=system
+ name="com.ubuntu.location.Service",
+
+dbus (receive, send)
+ bus=system
+ path=/com/ubuntu/location/Service{,/**}
+ interface=org.freedesktop.DBus**
+ peer=(label=unconfined),
+`)
+
+var locationControlConnectedSlotAppArmor = []byte(`
+# Allow connected clients to interact with the service
+
+# Allow clients to query/modify service properties
+dbus (receive)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member="{Get,Set}"
+ peer=(label=###PLUG_SECURITY_TAGS###),
+
+dbus (send)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member=PropertiesChanged
+ peer=(label=###PLUG_SECURITY_TAGS###),
+`)
+
+var locationControlConnectedPlugAppArmor = []byte(`
+# Description: Allow using location service. Reserved because this gives
+# privileged access to the service.
+# Usage: reserved
+
+#include
+
+# Allow clients to query service properties
+dbus (send)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member="{Get,Set}"
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+dbus (receive)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member=PropertiesChanged
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+dbus (receive)
+ bus=system
+ path=/
+ interface=org.freedesktop.DBus.ObjectManager
+ peer=(label=unconfined),
+`)
+
+var locationControlPermanentSlotSecComp = []byte(`
+getsockname
+recvmsg
+sendmsg
+sendto
+`)
+
+var locationControlConnectedPlugSecComp = []byte(`
+getsockname
+recvmsg
+sendmsg
+sendto
+`)
+
+var locationControlPermanentSlotDBus = []byte(`
+
+
+
+
+
+`)
+
+var locationControlConnectedPlugDBus = []byte(`
+
+
+
+
+
+`)
+
+type LocationControlInterface struct{}
+
+func (iface *LocationControlInterface) Name() string {
+ return "location-control"
+}
+
+func (iface *LocationControlInterface) PermanentPlugSnippet(plug *interfaces.Plug, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityDBus, interfaces.SecurityAppArmor, interfaces.SecuritySecComp, interfaces.SecurityUDev:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *LocationControlInterface) ConnectedPlugSnippet(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ old := []byte("###SLOT_SECURITY_TAGS###")
+ new := slotAppLabelExpr(slot)
+ snippet := bytes.Replace(locationControlConnectedPlugAppArmor, old, new, -1)
+ return snippet, nil
+ case interfaces.SecurityDBus:
+ return locationControlConnectedPlugDBus, nil
+ case interfaces.SecuritySecComp:
+ return locationControlConnectedPlugSecComp, nil
+ case interfaces.SecurityUDev:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *LocationControlInterface) PermanentSlotSnippet(slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ return locationControlPermanentSlotAppArmor, nil
+ case interfaces.SecurityDBus:
+ return locationControlPermanentSlotDBus, nil
+ case interfaces.SecuritySecComp:
+ return locationControlPermanentSlotSecComp, nil
+ case interfaces.SecurityUDev:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *LocationControlInterface) ConnectedSlotSnippet(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ old := []byte("###PLUG_SECURITY_TAGS###")
+ new := plugAppLabelExpr(plug)
+ snippet := bytes.Replace(locationControlConnectedSlotAppArmor, old, new, -1)
+ return snippet, nil
+ case interfaces.SecurityDBus, interfaces.SecuritySecComp, interfaces.SecurityUDev:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *LocationControlInterface) SanitizePlug(slot *interfaces.Plug) error {
+ return nil
+}
+
+func (iface *LocationControlInterface) SanitizeSlot(slot *interfaces.Slot) error {
+ return nil
+}
+
+func (iface *LocationControlInterface) AutoConnect() bool {
+ return false
+}
diff -Nru snapd-2.0.5/interfaces/builtin/location_control_test.go snapd-2.0.8/interfaces/builtin/location_control_test.go
--- snapd-2.0.5/interfaces/builtin/location_control_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/location_control_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,230 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package builtin_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
+)
+
+type LocationControlInterfaceSuite struct {
+ iface interfaces.Interface
+ slot *interfaces.Slot
+ plug *interfaces.Plug
+}
+
+var _ = Suite(&LocationControlInterfaceSuite{
+ iface: &builtin.LocationControlInterface{},
+ slot: &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "location"},
+ Name: "location",
+ Interface: "location-control",
+ },
+ },
+ plug: &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{SuggestedName: "location"},
+ Name: "location-client",
+ Interface: "location-control",
+ },
+ },
+})
+
+func (s *LocationControlInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "location-control")
+}
+
+// The label glob when all apps are bound to the location slot
+func (s *LocationControlInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelAll(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
+ app2 := &snap.AppInfo{Name: "app2"}
+ slot := &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.*"),`)
+}
+
+// The label uses alternation when some, but not all, apps is bound to the location slot
+func (s *LocationControlInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelSome(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
+ app2 := &snap.AppInfo{Name: "app2"}
+ app3 := &snap.AppInfo{Name: "app3"}
+ slot := &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2, "app3": app3},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.{app1,app2}"),`)
+}
+
+// The label uses short form when exactly one app is bound to the location slot
+func (s *LocationControlInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelOne(c *C) {
+ app := &snap.AppInfo{Name: "app"}
+ slot := &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.app"),`)
+}
+
+// The label glob when all apps are bound to the location plug
+func (s *LocationControlInterfaceSuite) TestConnectedSlotSnippetUsesPlugLabelAll(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
+ app2 := &snap.AppInfo{Name: "app2"}
+ plug := &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ snippet, err := s.iface.ConnectedSlotSnippet(plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.*"),`)
+}
+
+// The label uses alternation when some, but not all, apps is bound to the location plug
+func (s *LocationControlInterfaceSuite) TestConnectedSlotSnippetUsesPlugLabelSome(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
+ app2 := &snap.AppInfo{Name: "app2"}
+ app3 := &snap.AppInfo{Name: "app3"}
+ plug := &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2, "app3": app3},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ snippet, err := s.iface.ConnectedSlotSnippet(plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.{app1,app2}"),`)
+}
+
+// The label uses short form when exactly one app is bound to the location plug
+func (s *LocationControlInterfaceSuite) TestConnectedSlotSnippetUsesPlugLabelOne(c *C) {
+ app := &snap.AppInfo{Name: "app"}
+ plug := &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ }
+ snippet, err := s.iface.ConnectedSlotSnippet(plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.app"),`)
+}
+
+func (s *LocationControlInterfaceSuite) TestUnusedSecuritySystems(c *C) {
+ systems := [...]interfaces.SecuritySystem{interfaces.SecuritySecComp,
+ interfaces.SecurityDBus, interfaces.SecurityUDev}
+ for _, system := range systems {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityUDev)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, interfaces.SecurityUDev)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentPlugSnippet(s.plug, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+}
+
+func (s *LocationControlInterfaceSuite) TestUsedSecuritySystems(c *C) {
+ systems := [...]interfaces.SecuritySystem{interfaces.SecurityAppArmor,
+ interfaces.SecuritySecComp, interfaces.SecurityDBus}
+ for _, system := range systems {
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ }
+ snippet, err := s.iface.ConnectedSlotSnippet(s.plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+}
+
+func (s *LocationControlInterfaceSuite) TestUnexpectedSecuritySystems(c *C) {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+}
diff -Nru snapd-2.0.5/interfaces/builtin/location_observe.go snapd-2.0.8/interfaces/builtin/location_observe.go
--- snapd-2.0.5/interfaces/builtin/location_observe.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/location_observe.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,297 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package builtin
+
+import (
+ "bytes"
+
+ "github.com/snapcore/snapd/interfaces"
+)
+
+var locationObservePermanentSlotAppArmor = []byte(`
+# Description: Allow operating as the location service. Reserved because this
+# gives privileged access to the system.
+# Usage: reserved
+
+# DBus accesses
+#include
+dbus (send)
+ bus=system
+ path=/org/freedesktop/DBus
+ interface=org.freedesktop.DBus
+ member="{Request,Release}Name"
+ peer=(name=org.freedesktop.DBus, label=unconfined),
+
+dbus (send)
+ bus=system
+ path=/org/freedesktop/DBus
+ interface=org.freedesktop.DBus
+ member="GetConnectionUnix{ProcessID,User}"
+ peer=(label=unconfined),
+
+# Allow binding the service to the requested connection name
+dbus (bind)
+ bus=system
+ name="com.ubuntu.location.Service",
+
+dbus (receive, send)
+ bus=system
+ path=/com/ubuntu/location/Service{,/**}
+ interface=org.freedesktop.DBus**
+ peer=(label=unconfined),
+`)
+
+var locationObserveConnectedSlotAppArmor = []byte(`
+# Allow connected clients to interact with the service
+
+# Allow the service to host sessions
+dbus (bind)
+ bus=system
+ name="com.ubuntu.location.Service.Session",
+
+# Allow clients to create a session
+dbus (receive)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=com.ubuntu.location.Service
+ member=CreateSessionForCriteria
+ peer=(label=###PLUG_SECURITY_TAGS###),
+
+# Allow clients to query service properties
+dbus (receive)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member=Get
+ peer=(label=###PLUG_SECURITY_TAGS###),
+
+# Allow clients to request starting/stopping updates
+dbus (receive)
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member="{Start,Stop}PositionUpdates"
+ peer=(label=###PLUG_SECURITY_TAGS###),
+
+dbus (receive)
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member="{Start,Stop}HeadingUpdates"
+ peer=(label=###PLUG_SECURITY_TAGS###),
+
+dbus (receive)
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member="{Start,Stop}VelocityUpdates"
+ peer=(label=###PLUG_SECURITY_TAGS###),
+
+# Allow the service to send updates to clients
+dbus (send)
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member="Update{Position,Heading,Velocity}"
+ peer=(label=###PLUG_SECURITY_TAGS###),
+
+dbus (send)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member=PropertiesChanged
+ peer=(label=###PLUG_SECURITY_TAGS###),
+`)
+
+var locationObserveConnectedPlugAppArmor = []byte(`
+# Description: Allow using location service. Reserved because this gives
+# privileged access to the service.
+# Usage: reserved
+
+#include
+
+# Allow clients to query service properties
+dbus (send)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member=Get
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+# Allow clients to create a session
+dbus (send)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=com.ubuntu.location.Service
+ member=CreateSessionForCriteria
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+# Allow clients to request starting/stopping updates
+dbus (send)
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member="{Start,Stop}PositionUpdates"
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+dbus (send)
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member="{Start,Stop}HeadingUpdates"
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+dbus (send)
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member="{Start,Stop}VelocityUpdates"
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+# Allow clients to receive updates from the service
+dbus (receive)
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member="Update{Position,Heading,Velocity}"
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+dbus (receive)
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member=PropertiesChanged
+ peer=(label=###SLOT_SECURITY_TAGS###),
+
+dbus (receive)
+ bus=system
+ path=/
+ interface=org.freedesktop.DBus.ObjectManager
+ peer=(label=unconfined),
+`)
+
+var locationObservePermanentSlotSecComp = []byte(`
+getsockname
+recvmsg
+sendmsg
+sendto
+`)
+
+var locationObserveConnectedPlugSecComp = []byte(`
+getsockname
+recvmsg
+sendmsg
+sendto
+`)
+
+var locationObservePermanentSlotDBus = []byte(`
+
+
+
+
+
+
+
+
+`)
+
+var locationObserveConnectedPlugDBus = []byte(`
+
+
+
+
+
+
+
+`)
+
+type LocationObserveInterface struct{}
+
+func (iface *LocationObserveInterface) Name() string {
+ return "location-observe"
+}
+
+func (iface *LocationObserveInterface) PermanentPlugSnippet(plug *interfaces.Plug, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityDBus, interfaces.SecurityAppArmor, interfaces.SecuritySecComp, interfaces.SecurityUDev:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *LocationObserveInterface) ConnectedPlugSnippet(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ old := []byte("###SLOT_SECURITY_TAGS###")
+ new := slotAppLabelExpr(slot)
+ snippet := bytes.Replace(locationObserveConnectedPlugAppArmor, old, new, -1)
+ return snippet, nil
+ case interfaces.SecurityDBus:
+ return locationObserveConnectedPlugDBus, nil
+ case interfaces.SecuritySecComp:
+ return locationObserveConnectedPlugSecComp, nil
+ case interfaces.SecurityUDev:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *LocationObserveInterface) PermanentSlotSnippet(slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ return locationObservePermanentSlotAppArmor, nil
+ case interfaces.SecurityDBus:
+ return locationObservePermanentSlotDBus, nil
+ case interfaces.SecuritySecComp:
+ return locationObservePermanentSlotSecComp, nil
+ case interfaces.SecurityUDev:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *LocationObserveInterface) ConnectedSlotSnippet(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ old := []byte("###PLUG_SECURITY_TAGS###")
+ new := plugAppLabelExpr(plug)
+ snippet := bytes.Replace(locationObserveConnectedSlotAppArmor, old, new, -1)
+ return snippet, nil
+ case interfaces.SecurityDBus, interfaces.SecuritySecComp, interfaces.SecurityUDev:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *LocationObserveInterface) SanitizePlug(slot *interfaces.Plug) error {
+ return nil
+}
+
+func (iface *LocationObserveInterface) SanitizeSlot(slot *interfaces.Slot) error {
+ return nil
+}
+
+func (iface *LocationObserveInterface) AutoConnect() bool {
+ return false
+}
diff -Nru snapd-2.0.5/interfaces/builtin/location_observe_test.go snapd-2.0.8/interfaces/builtin/location_observe_test.go
--- snapd-2.0.5/interfaces/builtin/location_observe_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/location_observe_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,230 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package builtin_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
+)
+
+type LocationObserveInterfaceSuite struct {
+ iface interfaces.Interface
+ slot *interfaces.Slot
+ plug *interfaces.Plug
+}
+
+var _ = Suite(&LocationObserveInterfaceSuite{
+ iface: &builtin.LocationObserveInterface{},
+ slot: &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "location"},
+ Name: "location",
+ Interface: "location-observe",
+ },
+ },
+ plug: &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{SuggestedName: "location"},
+ Name: "location-client",
+ Interface: "location-observe",
+ },
+ },
+})
+
+func (s *LocationObserveInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "location-observe")
+}
+
+// The label glob when all apps are bound to the location slot
+func (s *LocationObserveInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelAll(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
+ app2 := &snap.AppInfo{Name: "app2"}
+ slot := &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.*"),`)
+}
+
+// The label uses alternation when some, but not all, apps is bound to the location slot
+func (s *LocationObserveInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelSome(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
+ app2 := &snap.AppInfo{Name: "app2"}
+ app3 := &snap.AppInfo{Name: "app3"}
+ slot := &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2, "app3": app3},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.{app1,app2}"),`)
+}
+
+// The label uses short form when exactly one app is bound to the location slot
+func (s *LocationObserveInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelOne(c *C) {
+ app := &snap.AppInfo{Name: "app"}
+ slot := &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.app"),`)
+}
+
+// The label glob when all apps are bound to the location plug
+func (s *LocationObserveInterfaceSuite) TestConnectedSlotSnippetUsesPlugLabelAll(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
+ app2 := &snap.AppInfo{Name: "app2"}
+ plug := &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ snippet, err := s.iface.ConnectedSlotSnippet(plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.*"),`)
+}
+
+// The label uses alternation when some, but not all, apps is bound to the location plug
+func (s *LocationObserveInterfaceSuite) TestConnectedSlotSnippetUsesPlugLabelSome(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
+ app2 := &snap.AppInfo{Name: "app2"}
+ app3 := &snap.AppInfo{Name: "app3"}
+ plug := &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2, "app3": app3},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ snippet, err := s.iface.ConnectedSlotSnippet(plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.{app1,app2}"),`)
+}
+
+// The label uses short form when exactly one app is bound to the location plug
+func (s *LocationObserveInterfaceSuite) TestConnectedSlotSnippetUsesPlugLabelOne(c *C) {
+ app := &snap.AppInfo{Name: "app"}
+ plug := &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{
+ SuggestedName: "location",
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ Name: "location",
+ Interface: "location",
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ }
+ snippet, err := s.iface.ConnectedSlotSnippet(plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, `peer=(label="snap.location.app"),`)
+}
+
+func (s *LocationObserveInterfaceSuite) TestUnusedSecuritySystems(c *C) {
+ systems := [...]interfaces.SecuritySystem{interfaces.SecuritySecComp,
+ interfaces.SecurityDBus, interfaces.SecurityUDev}
+ for _, system := range systems {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityUDev)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, interfaces.SecurityUDev)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentPlugSnippet(s.plug, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+}
+
+func (s *LocationObserveInterfaceSuite) TestUsedSecuritySystems(c *C) {
+ systems := [...]interfaces.SecuritySystem{interfaces.SecurityAppArmor,
+ interfaces.SecuritySecComp, interfaces.SecurityDBus}
+ for _, system := range systems {
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ }
+ snippet, err := s.iface.ConnectedSlotSnippet(s.plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+}
+
+func (s *LocationObserveInterfaceSuite) TestUnexpectedSecuritySystems(c *C) {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+}
diff -Nru snapd-2.0.5/interfaces/builtin/log_observe.go snapd-2.0.8/interfaces/builtin/log_observe.go
--- snapd-2.0.5/interfaces/builtin/log_observe.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/log_observe.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/log-observe
@@ -32,8 +32,12 @@
/var/log/** r,
# Allow sysctl -w kernel.printk_ratelimit=#
+/{,usr/}sbin/sysctl ixr,
@{PROC}/sys/kernel/printk_ratelimit rw,
+# Allow resolving kernel seccomp denials
+/usr/bin/scmp_sys_resolver ixr,
+
# Needed since we are root and the owner/group doesn't match :\
# So long as we have this, the cap must be reserved.
capability dac_override,
diff -Nru snapd-2.0.5/interfaces/builtin/log_observe_test.go snapd-2.0.8/interfaces/builtin/log_observe_test.go
--- snapd-2.0.5/interfaces/builtin/log_observe_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/log_observe_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type LogObserveInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/mount_observe.go snapd-2.0.8/interfaces/builtin/mount_observe.go
--- snapd-2.0.5/interfaces/builtin/mount_observe.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/mount_observe.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/mount-observe
diff -Nru snapd-2.0.5/interfaces/builtin/mount_observe_test.go snapd-2.0.8/interfaces/builtin/mount_observe_test.go
--- snapd-2.0.5/interfaces/builtin/mount_observe_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/mount_observe_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type MountObserveInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/network_bind.go snapd-2.0.8/interfaces/builtin/network_bind.go
--- snapd-2.0.5/interfaces/builtin/network_bind.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_bind.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/network-bind
@@ -89,7 +89,7 @@
# of socket(), bind(), connect(), etc individually. While we could allow it,
# we wouldn't be able to properly arg filter socketcall for AF_INET/AF_INET6
# when LP: #1446748 is implemented.
-#socketcall
+socketcall
`
// NewNetworkBindInterface returns a new "network-bind" interface.
diff -Nru snapd-2.0.5/interfaces/builtin/network_bind_test.go snapd-2.0.8/interfaces/builtin/network_bind_test.go
--- snapd-2.0.5/interfaces/builtin/network_bind_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_bind_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type NetworkBindInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/network_control.go snapd-2.0.8/interfaces/builtin/network_control.go
--- snapd-2.0.5/interfaces/builtin/network_control.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_control.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/network-control
@@ -68,11 +68,9 @@
/{,usr/}{,s}bin/bridge ixr,
/{,usr/}{,s}bin/dhclient Pxr, # use ixr instead if want to limit to snap dirs
/{,usr/}{,s}bin/ifconfig ixr,
-audit deny /{,usr/}{,s}bin/if{up,down} r, # the system uses these, snaps shouldn't
/{,usr/}{,s}bin/ip ixr,
/{,usr/}{,s}bin/ipmaddr ixr,
/{,usr/}{,s}bin/iptunnel ixr,
-audit deny /{,usr/}{,s}bin/mii-tool r, # needs capability sys_module
/{,usr/}{,s}bin/nameif ixr,
/{,usr/}{,s}bin/netstat ixr, # -p not supported
/{,usr/}{,s}bin/nstat ixr,
diff -Nru snapd-2.0.5/interfaces/builtin/network_control_test.go snapd-2.0.8/interfaces/builtin/network_control_test.go
--- snapd-2.0.5/interfaces/builtin/network_control_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_control_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type NetworkControlInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/network.go snapd-2.0.8/interfaces/builtin/network.go
--- snapd-2.0.5/interfaces/builtin/network.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network.go 2016-06-08 05:58:01.000000000 +0000
@@ -19,7 +19,7 @@
package builtin
-import "github.com/ubuntu-core/snappy/interfaces"
+import "github.com/snapcore/snapd/interfaces"
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/network
const networkConnectedPlugAppArmor = `
@@ -57,7 +57,7 @@
# of socket(), bind(), connect(), etc individually. While we could allow it,
# we wouldn't be able to properly arg filter socketcall for AF_INET/AF_INET6
# when LP: #1446748 is implemented.
-#socketcall
+socketcall
`
// NewNetworkInterface returns a new "network" interface.
diff -Nru snapd-2.0.5/interfaces/builtin/network_manager.go snapd-2.0.8/interfaces/builtin/network_manager.go
--- snapd-2.0.5/interfaces/builtin/network_manager.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_manager.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,8 +22,8 @@
import (
"bytes"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/release"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/release"
)
var networkManagerPermanentSlotAppArmor = []byte(`
diff -Nru snapd-2.0.5/interfaces/builtin/network_manager_test.go snapd-2.0.8/interfaces/builtin/network_manager_test.go
--- snapd-2.0.5/interfaces/builtin/network_manager_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_manager_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,11 +22,11 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/release"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
)
type NetworkManagerInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/network_observe.go snapd-2.0.8/interfaces/builtin/network_observe.go
--- snapd-2.0.5/interfaces/builtin/network_observe.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_observe.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/network-observe
diff -Nru snapd-2.0.5/interfaces/builtin/network_observe_test.go snapd-2.0.8/interfaces/builtin/network_observe_test.go
--- snapd-2.0.5/interfaces/builtin/network_observe_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_observe_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type NetworkObserveInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/network_test.go snapd-2.0.8/interfaces/builtin/network_test.go
--- snapd-2.0.5/interfaces/builtin/network_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/network_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type NetworkInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/opengl.go snapd-2.0.8/interfaces/builtin/opengl.go
--- snapd-2.0.5/interfaces/builtin/opengl.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/opengl.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,23 +20,26 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
const openglConnectedPlugAppArmor = `
-# Description: Can access opengl.
+# Description: Can access opengl.
# Usage: reserved
# specific gl libs
/var/lib/snapd/lib/gl/** rm,
# nvidia
- /proc/driver/nvidia/params r,
- /sys/bus/pci/devices/** r,
+ @{PROC}/driver/nvidia/params r,
+ @{PROC}/modules r,
/dev/nvidiactl rw,
- /proc/modules r,
/dev/nvidia-modeset rw,
/dev/nvidia* rw,
+
+ # FIXME: this is an information leak and snapd should instead query udev for
+ # the specific accesses associated with the above devices.
+ /sys/bus/pci/devices/** r,
`
const openglConnectedPlugSecComp = `
diff -Nru snapd-2.0.5/interfaces/builtin/pulseaudio.go snapd-2.0.8/interfaces/builtin/pulseaudio.go
--- snapd-2.0.5/interfaces/builtin/pulseaudio.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/pulseaudio.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,49 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package builtin
+
+import (
+ "github.com/snapcore/snapd/interfaces"
+)
+
+const pulseaudioConnectedPlugAppArmor = `
+/etc/pulse/ r,
+/etc/pulse/* r,
+/{run,dev}/shm/pulse-shm-* rk,
+owner /{,var/}run/user/*/pulse/ r,
+owner /{,var/}run/user/*/pulse/native rwk,
+`
+
+const pulseaudioConnectedPlugSecComp = `
+setsockopt
+connect
+sendto
+`
+
+// NewPulseAudioInterface returns a new "pulseaudio" interface.
+func NewPulseAudioInterface() interfaces.Interface {
+ return &commonInterface{
+ name: "pulseaudio",
+ connectedPlugAppArmor: pulseaudioConnectedPlugAppArmor,
+ connectedPlugSecComp: pulseaudioConnectedPlugSecComp,
+ reservedForOS: true,
+ autoConnect: true,
+ }
+}
diff -Nru snapd-2.0.5/interfaces/builtin/snapd_control.go snapd-2.0.8/interfaces/builtin/snapd_control.go
--- snapd-2.0.5/interfaces/builtin/snapd_control.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/snapd_control.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/snapd-control
diff -Nru snapd-2.0.5/interfaces/builtin/snapd_control_test.go snapd-2.0.8/interfaces/builtin/snapd_control_test.go
--- snapd-2.0.5/interfaces/builtin/snapd_control_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/snapd_control_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type SnapdControlInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/system_observe.go snapd-2.0.8/interfaces/builtin/system_observe.go
--- snapd-2.0.5/interfaces/builtin/system_observe.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/system_observe.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/system-observe
@@ -48,6 +48,14 @@
# Other miscellaneous accesses for observing the system
@{PROC}/vmstat r,
+
+# These are not process-specific (/proc/*/... and /proc/*/task/*/...)
+@{PROC}/*/{,task/,task/*/} r,
+@{PROC}/*/{,task/*/}auxv r,
+@{PROC}/*/{,task/*/}cmdline r,
+@{PROC}/*/{,task/*/}stat r,
+@{PROC}/*/{,task/*/}statm r,
+@{PROC}/*/{,task/*/}status r,
`
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/seccomp/policygroups/ubuntu-core/16.04/system-observe
diff -Nru snapd-2.0.5/interfaces/builtin/system_observe_test.go snapd-2.0.8/interfaces/builtin/system_observe_test.go
--- snapd-2.0.5/interfaces/builtin/system_observe_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/system_observe_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type SystemObserveInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/timeserver_control.go snapd-2.0.8/interfaces/builtin/timeserver_control.go
--- snapd-2.0.5/interfaces/builtin/timeserver_control.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/timeserver_control.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/timeserver-control
diff -Nru snapd-2.0.5/interfaces/builtin/timeserver_control_test.go snapd-2.0.8/interfaces/builtin/timeserver_control_test.go
--- snapd-2.0.5/interfaces/builtin/timeserver_control_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/timeserver_control_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type TimeserverControlInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/timezone_control.go snapd-2.0.8/interfaces/builtin/timezone_control.go
--- snapd-2.0.5/interfaces/builtin/timezone_control.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/timezone_control.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/timezone-control
diff -Nru snapd-2.0.5/interfaces/builtin/timezone_control_test.go snapd-2.0.8/interfaces/builtin/timezone_control_test.go
--- snapd-2.0.5/interfaces/builtin/timezone_control_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/timezone_control_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type TimezoneControlInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/unity7.go snapd-2.0.8/interfaces/builtin/unity7.go
--- snapd-2.0.5/interfaces/builtin/unity7.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/unity7.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/unity7
@@ -66,12 +66,102 @@
#owner @{HOME}/.themes/** r,
+# input methods (ibus)
# subset of ibus abstraction
/usr/lib/@{multiarch}/gtk-2.0/[0-9]*/immodules/im-ibus.so mr,
owner @{HOME}/.config/ibus/ r,
owner @{HOME}/.config/ibus/bus/ r,
owner @{HOME}/.config/ibus/bus/* r,
+# allow communicating with ibus-daemon (this allows sniffing key events)
+unix (connect, receive, send)
+ type=stream
+ peer=(addr="@/tmp/ibus/dbus-*"),
+
+
+# input methods (mozc)
+# allow communicating with mozc server (TODO: investigate if allows sniffing)
+unix (connect, receive, send)
+ type=stream
+ peer=(addr="@tmp/.mozc.*"),
+
+
+# input methods (fcitx)
+# allow communicating with fcitx dbus service
+dbus send
+ bus=fcitx
+ path=/org/freedesktop/DBus
+ interface=org.freedesktop.DBus
+ member={Hello,AddMatch,RemoveMatch,GetNameOwner,NameHasOwner,StartServiceByName}
+ peer=(name=org.freedesktop.DBus),
+
+owner @{HOME}/.config/fcitx/dbus/* r,
+
+# allow creating an input context
+dbus send
+ bus=fcitx
+ path=/inputmethod
+ interface=org.fcitx.Fcitx.InputMethod
+ member=CreateIC*
+ peer=(label=unconfined),
+
+# allow setting up and tearing down the input context
+dbus send
+ bus=fcitx
+ path=/inputcontext_[0-9]*
+ interface=org.fcitx.Fcitx.InputContext
+ member="{Close,Destroy,Enable}IC"
+ peer=(label=unconfined),
+
+dbus send
+ bus=fcitx
+ path=/inputcontext_[0-9]*
+ interface=org.fcitx.Fcitx.InputContext
+ member=Reset
+ peer=(label=unconfined),
+
+# allow service to send us signals
+dbus receive
+ bus=fcitx
+ peer=(label=unconfined),
+
+# use the input context
+dbus send
+ bus=fcitx
+ path=/inputcontext_[0-9]*
+ interface=org.fcitx.Fcitx.InputContext
+ member="Focus{In,Out}"
+ peer=(label=unconfined),
+
+dbus send
+ bus=fcitx
+ path=/inputcontext_[0-9]*
+ interface=org.fcitx.Fcitx.InputContext
+ member="{CommitPreedit,Set*}"
+ peer=(label=unconfined),
+
+# this is an information leak and allows key and mouse sniffing. If the input
+# context path were tied to the process' security label, this would not be an
+# issue.
+dbus send
+ bus=fcitx
+ path=/inputcontext_[0-9]*
+ interface=org.fcitx.Fcitx.InputContext
+ member="{MouseEvent,ProcessKeyEvent}"
+ peer=(label=unconfined),
+
+# this method does not exist with the sunpinyin backend (at least), so allow
+# it for other input methods. This may consitute an information leak (which,
+# again, could be avoided if the path were tied to the process' security
+# label).
+dbus send
+ bus=fcitx
+ path=/inputcontext_[0-9]*
+ interface=org.freedesktop.DBus.Properties
+ member=GetAll
+ peer=(label=unconfined),
+
+
# subset of freedesktop.org
/usr/share/mime/** r,
owner @{HOME}/.local/share/mime/** r,
@@ -117,32 +207,43 @@
peer=(label=unconfined),
# gmenu
+# Note: the gmenu DBus api was not designed for application isolation and apps
+# may specify anything as their 'path'. For example, these work in the many
+# cases:
+# - /org/gtk/Application/anonymous{,/**}
+# - /com/canonical/unity/gtk/window/[0-9]*
+# but libreoffice does:
+# - /org/libreoffice{,/**}
+# As such, cannot mediate by DBus path so we'll be as strict as we can in the
+# other mediated parts
dbus (send)
bus=session
interface=org.gtk.Actions
- path={/org/gtk/Application/anonymous{,/**},/com/canonical/unity/gtk/window/[0-9]*}
member=Changed
- peer=(label=unconfined),
+ peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (receive)
bus=session
interface=org.gtk.Actions
- path={/org/gtk/Application/anonymous{,/**},/com/canonical/unity/gtk/window/[0-9]*}
member={Activate,DescribeAll,SetState}
peer=(label=unconfined),
dbus (receive)
bus=session
interface=org.gtk.Menus
- path={/org/gtk/Application/anonymous{,/**},/com/canonical/unity/gtk/window/[0-9]*}
member={Start,End}
peer=(label=unconfined),
-dbus (receive,send)
+dbus (send)
bus=session
interface=org.gtk.Menus
- path={/org/gtk/Application/anonymous{,/**},/com/canonical/unity/gtk/window/[0-9]*}
member=Changed
+ peer=(name=org.freedesktop.DBus, label=unconfined),
+
+# url helper
+dbus (send)
+ bus=session
+ interface=com.canonical.SafeLauncher.OpenURL
peer=(label=unconfined),
# dbusmenu
@@ -228,11 +329,71 @@
member=NotificationClosed
peer=(label=unconfined),
+# unity launcher
+dbus (send)
+ bus=session
+ path=/com/canonical/unity/launcherentry/[0-9]*
+ interface=com.canonical.Unity.LauncherEntry
+ member=Update
+ peer=(name=org.freedesktop.DBus, label=unconfined),
+
+dbus (send)
+ bus=session
+ path=/com/canonical/unity/launcherentry/[0-9]*
+ interface=com.canonical.dbusmenu
+ member="{LayoutUpdated,ItemsPropertiesUpdated}"
+ peer=(name=org.freedesktop.DBus, label=unconfined),
+
+dbus (receive)
+ bus=session
+ path=/com/canonical/unity/launcherentry/[0-9]*
+ interface="{com.canonical.dbusmenu,org.freedesktop.DBus.Properties}"
+ member=Get*
+ peer=(label=unconfined),
+
+# This rule is meant to be covered by abstractions/dbus-session-strict but
+# the unity launcher code has a typo that uses /org/freedesktop/dbus as the
+# path instead of /org/freedesktop/DBus, so we need to all it here.
+dbus (send)
+ bus=session
+ path=/org/freedesktop/dbus
+ interface=org.freedesktop.DBus
+ member=NameHasOwner
+ peer=(name=org.freedesktop.DBus, label=unconfined),
+
+# appmenu
+dbus (send)
+ bus=session
+ path=/org/freedesktop/DBus
+ interface=org.freedesktop.DBus
+ member=ListNames
+ peer=(name=org.freedesktop.DBus, label=unconfined),
+
+dbus (send)
+ bus=session
+ path=/com/canonical/AppMenu/Registrar
+ interface=com.canonical.AppMenu.Registrar
+ member="{RegisterWindow,UnregisterWindow}"
+ peer=(label=unconfined),
+
+dbus (send)
+ bus=session
+ path=/com/canonical/AppMenu/Registrar
+ interface=com.canonical.dbusmenu
+ member=UnregisterWindow
+ peer=(label=unconfined),
+
+dbus (receive)
+ bus=session
+ path=/com/canonical/menu/[0-9]*
+ interface="{org.freedesktop.DBus.Properties,com.canonical.dbusmenu}"
+ member="{GetAll,GetLayout}"
+ peer=(label=unconfined),
+
+
# Lttng tracing is very noisy and should not be allowed by confined apps. Can
# safely deny. LP: #1260491
deny /{,var/}run/shm/lttng-ust-* r,
-
-# TODO: pull in modern items from ubuntu-unity7-base abstraction, eg, HUD, etc
`
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/seccomp/policygroups/ubuntu-core/16.04/unity7
diff -Nru snapd-2.0.5/interfaces/builtin/unity7_test.go snapd-2.0.8/interfaces/builtin/unity7_test.go
--- snapd-2.0.5/interfaces/builtin/unity7_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/unity7_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,9 +22,9 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
)
type Unity7InterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/builtin/utils.go snapd-2.0.8/interfaces/builtin/utils.go
--- snapd-2.0.5/interfaces/builtin/utils.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/utils.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,28 +24,29 @@
"fmt"
"sort"
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/snap"
)
-// slotAppLabelExpr returns the specification of the apparmor label describing
+// AppLabelExpr returns the specification of the apparmor label describing
// all the apps bound to a given slot. The result has one of three forms,
// depending on how apps are bound to the slot:
//
// - "snap.$snap.$app" if there is exactly one app bound
// - "snap.$snap.{$app1,...$appN}" if there are some, but not all, apps bound
// - "snap.$snap.*" if all apps are bound to the slot
-func slotAppLabelExpr(slot *interfaces.Slot) []byte {
+func appLabelExpr(apps map[string]*snap.AppInfo, snap *snap.Info) []byte {
var buf bytes.Buffer
- fmt.Fprintf(&buf, `"snap.%s.`, slot.Snap.Name())
- if len(slot.Apps) == 1 {
- for appName := range slot.Apps {
+ fmt.Fprintf(&buf, `"snap.%s.`, snap.Name())
+ if len(apps) == 1 {
+ for appName := range apps {
buf.WriteString(appName)
}
- } else if len(slot.Apps) == len(slot.Snap.Apps) {
+ } else if len(apps) == len(snap.Apps) {
buf.WriteByte('*')
} else {
- appNames := make([]string, 0, len(slot.Apps))
- for appName := range slot.Apps {
+ appNames := make([]string, 0, len(apps))
+ for appName := range apps {
appNames = append(appNames, appName)
}
sort.Strings(appNames)
@@ -60,3 +61,11 @@
buf.WriteByte('"')
return buf.Bytes()
}
+
+func slotAppLabelExpr(slot *interfaces.Slot) []byte {
+ return appLabelExpr(slot.Apps, slot.Snap)
+}
+
+func plugAppLabelExpr(plug *interfaces.Plug) []byte {
+ return appLabelExpr(plug.Apps, plug.Snap)
+}
diff -Nru snapd-2.0.5/interfaces/builtin/x11.go snapd-2.0.8/interfaces/builtin/x11.go
--- snapd-2.0.5/interfaces/builtin/x11.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/x11.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package builtin
import (
- "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/snapcore/snapd/interfaces"
)
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/x
diff -Nru snapd-2.0.5/interfaces/builtin/x11_test.go snapd-2.0.8/interfaces/builtin/x11_test.go
--- snapd-2.0.5/interfaces/builtin/x11_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/builtin/x11_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,10 +22,10 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
)
type X11InterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/core.go snapd-2.0.8/interfaces/core.go
--- snapd-2.0.5/interfaces/core.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/core.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
"fmt"
"regexp"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
// Plug represents the potential of a given snap to connect to a slot.
diff -Nru snapd-2.0.5/interfaces/core_test.go snapd-2.0.8/interfaces/core_test.go
--- snapd-2.0.5/interfaces/core_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/core_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/interfaces"
+ . "github.com/snapcore/snapd/interfaces"
)
func Test(t *testing.T) {
diff -Nru snapd-2.0.5/interfaces/dbus/backend.go snapd-2.0.8/interfaces/dbus/backend.go
--- snapd-2.0.5/interfaces/dbus/backend.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/dbus/backend.go 2016-06-08 05:58:01.000000000 +0000
@@ -32,10 +32,10 @@
"fmt"
"os"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
)
// Backend is responsible for maintaining DBus policy files.
diff -Nru snapd-2.0.5/interfaces/dbus/backend_test.go snapd-2.0.8/interfaces/dbus/backend_test.go
--- snapd-2.0.5/interfaces/dbus/backend_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/dbus/backend_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,10 +26,10 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/dbus"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/dbus"
+ "github.com/snapcore/snapd/snap"
)
type backendSuite struct {
diff -Nru snapd-2.0.5/interfaces/dbus/dbus_test.go snapd-2.0.8/interfaces/dbus/dbus_test.go
--- snapd-2.0.5/interfaces/dbus/dbus_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/dbus/dbus_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"testing"
- "github.com/ubuntu-core/snappy/interfaces/dbus"
+ "github.com/snapcore/snapd/interfaces/dbus"
. "gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/interfaces/json_test.go snapd-2.0.8/interfaces/json_test.go
--- snapd-2.0.5/interfaces/json_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/json_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,8 +24,8 @@
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/snap"
+ . "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/snap"
)
type JSONSuite struct{}
diff -Nru snapd-2.0.5/interfaces/naming_test.go snapd-2.0.8/interfaces/naming_test.go
--- snapd-2.0.5/interfaces/naming_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/naming_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/interfaces"
+ . "github.com/snapcore/snapd/interfaces"
)
type NamingSuite struct{}
diff -Nru snapd-2.0.5/interfaces/repo.go snapd-2.0.8/interfaces/repo.go
--- snapd-2.0.5/interfaces/repo.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/repo.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
"strings"
"sync"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
// Repository stores all known snappy plugs and slots and ifaces.
diff -Nru snapd-2.0.5/interfaces/repo_test.go snapd-2.0.8/interfaces/repo_test.go
--- snapd-2.0.5/interfaces/repo_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/repo_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,9 +24,9 @@
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
+ . "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
)
type RepositorySuite struct {
diff -Nru snapd-2.0.5/interfaces/seccomp/backend.go snapd-2.0.8/interfaces/seccomp/backend.go
--- snapd-2.0.5/interfaces/seccomp/backend.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/seccomp/backend.go 2016-06-08 05:58:01.000000000 +0000
@@ -37,10 +37,10 @@
"fmt"
"os"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
)
// Backend is responsible for maintaining seccomp profiles for ubuntu-core-launcher.
diff -Nru snapd-2.0.5/interfaces/seccomp/backend_test.go snapd-2.0.8/interfaces/seccomp/backend_test.go
--- snapd-2.0.5/interfaces/seccomp/backend_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/seccomp/backend_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,11 +26,11 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/seccomp"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/seccomp"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
)
type backendSuite struct {
diff -Nru snapd-2.0.5/interfaces/testbackend.go snapd-2.0.8/interfaces/testbackend.go
--- snapd-2.0.5/interfaces/testbackend.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/testbackend.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package interfaces
import (
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
// TestSecurityBackend is a security backend intended for testing.
diff -Nru snapd-2.0.5/interfaces/testtype_test.go snapd-2.0.8/interfaces/testtype_test.go
--- snapd-2.0.5/interfaces/testtype_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/testtype_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,8 +24,8 @@
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/snap"
+ . "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/snap"
)
type TestInterfaceSuite struct {
diff -Nru snapd-2.0.5/interfaces/udev/backend.go snapd-2.0.8/interfaces/udev/backend.go
--- snapd-2.0.5/interfaces/udev/backend.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/udev/backend.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,10 +29,10 @@
"fmt"
"os"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
)
// Backend is responsible for maintaining udev rules.
diff -Nru snapd-2.0.5/interfaces/udev/backend_test.go snapd-2.0.8/interfaces/udev/backend_test.go
--- snapd-2.0.5/interfaces/udev/backend_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/udev/backend_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,11 +26,11 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/udev"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/udev"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
)
type backendSuite struct {
diff -Nru snapd-2.0.5/interfaces/udev/udev_test.go snapd-2.0.8/interfaces/udev/udev_test.go
--- snapd-2.0.5/interfaces/udev/udev_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/interfaces/udev/udev_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,8 +24,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/interfaces/udev"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/interfaces/udev"
+ "github.com/snapcore/snapd/testutil"
)
func Test(t *testing.T) {
diff -Nru snapd-2.0.5/logger/logger_test.go snapd-2.0.8/logger/logger_test.go
--- snapd-2.0.5/logger/logger_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/logger/logger_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
"os"
"testing"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/testutil"
. "gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/mkversion.sh snapd-2.0.8/mkversion.sh
--- snapd-2.0.5/mkversion.sh 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/mkversion.sh 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,18 @@
+#!/bin/sh
+set -e
+
+if [ -z "$GOPACKAGE" ]; then
+ # not being run from 'go generate'
+ cd "$(dirname "$0")"/cmd
+fi
+
+v="$( git describe --dirty --always | sed -e 's/-/+git/;y/-/./' )"
+
+cat < version_generated.go
+// generated by mkversion.sh; do not edit
+package cmd
+
+func init() {
+ Version = "$v"
+}
+EOF
diff -Nru snapd-2.0.5/notifications/subscriber.go snapd-2.0.8/notifications/subscriber.go
--- snapd-2.0.5/notifications/subscriber.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/notifications/subscriber.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
"github.com/gorilla/websocket"
- "github.com/ubuntu-core/snappy/strutil"
+ "github.com/snapcore/snapd/strutil"
)
// A Subscriber is interested in receiving notifications
diff -Nru snapd-2.0.5/osutil/io.go snapd-2.0.8/osutil/io.go
--- snapd-2.0.5/osutil/io.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/osutil/io.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,7 +23,7 @@
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/strutil"
+ "github.com/snapcore/snapd/strutil"
)
// AtomicWriteFlags are a bitfield of flags for AtomicWriteFile
diff -Nru snapd-2.0.5/osutil/io_test.go snapd-2.0.8/osutil/io_test.go
--- snapd-2.0.5/osutil/io_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/osutil/io_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,7 +25,7 @@
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/strutil"
+ "github.com/snapcore/snapd/strutil"
. "gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/osutil/sync_dir_test.go snapd-2.0.8/osutil/sync_dir_test.go
--- snapd-2.0.5/osutil/sync_dir_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/osutil/sync_dir_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
type EnsureDirStateSuite struct {
diff -Nru snapd-2.0.5/overlord/assertstate/assertmgr.go snapd-2.0.8/overlord/assertstate/assertmgr.go
--- snapd-2.0.5/overlord/assertstate/assertmgr.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/assertstate/assertmgr.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,11 +24,11 @@
import (
"os"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/state"
)
// AssertManager is responsible for the enforcement of assertions in
diff -Nru snapd-2.0.5/overlord/assertstate/assertmgr_test.go snapd-2.0.8/overlord/assertstate/assertmgr_test.go
--- snapd-2.0.5/overlord/assertstate/assertmgr_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/assertstate/assertmgr_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,11 +24,11 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/dirs"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/dirs"
- "github.com/ubuntu-core/snappy/overlord/assertstate"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/assertstate"
+ "github.com/snapcore/snapd/overlord/state"
)
func TestAssertManager(t *testing.T) { TestingT(t) }
diff -Nru snapd-2.0.5/overlord/auth/auth.go snapd-2.0.8/overlord/auth/auth.go
--- snapd-2.0.5/overlord/auth/auth.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/auth/auth.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,7 +25,7 @@
"net/http"
"sort"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/state"
)
// AuthState represents current authenticated users as tracked in state
diff -Nru snapd-2.0.5/overlord/auth/auth_test.go snapd-2.0.8/overlord/auth/auth_test.go
--- snapd-2.0.5/overlord/auth/auth_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/auth/auth_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,8 +25,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/overlord/auth"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/auth"
+ "github.com/snapcore/snapd/overlord/state"
)
// Hook up gocheck into the "go test" runner.
diff -Nru snapd-2.0.5/overlord/backend.go snapd-2.0.8/overlord/backend.go
--- snapd-2.0.5/overlord/backend.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/backend.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
"time"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
type overlordStateBackend struct {
diff -Nru snapd-2.0.5/overlord/firstboot.go snapd-2.0.8/overlord/firstboot.go
--- snapd-2.0.5/overlord/firstboot.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/firstboot.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,11 +22,11 @@
import (
"fmt"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snappy"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snappy"
)
func populateStateFromInstalled() error {
diff -Nru snapd-2.0.5/overlord/ifacestate/handlers.go snapd-2.0.8/overlord/ifacestate/handlers.go
--- snapd-2.0.5/overlord/ifacestate/handlers.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/ifacestate/handlers.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,11 +24,11 @@
"gopkg.in/tomb.v2"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snap"
)
func (m *InterfaceManager) doSetupProfiles(task *state.Task, _ *tomb.Tomb) error {
@@ -55,11 +55,7 @@
// Set DevMode flag if SnapSetup.Flags indicates it should be done
// but remember the old value in the task in case we undo.
task.Set("old-devmode", snapState.DevMode())
- if ss.DevMode() {
- snapState.Flags |= snapstate.DevMode
- } else {
- snapState.Flags &= ^snapstate.DevMode
- }
+ snapState.SetDevMode(ss.DevMode())
snapstate.Set(task.State(), snapName, &snapState)
// The snap may have been updated so perform the following operation to
@@ -143,11 +139,7 @@
}
// Restore the state of DevMode flag if old-devmode was saved in the task.
if err == nil {
- if oldDevMode {
- snapState.Flags |= snapstate.DevMode
- } else {
- snapState.Flags &= ^snapstate.DevMode
- }
+ snapState.SetDevMode(oldDevMode)
snapstate.Set(st, snapName, &snapState)
}
diff -Nru snapd-2.0.5/overlord/ifacestate/helpers.go snapd-2.0.8/overlord/ifacestate/helpers.go
--- snapd-2.0.5/overlord/ifacestate/helpers.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/ifacestate/helpers.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,16 +23,17 @@
"fmt"
"strings"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/interfaces/apparmor"
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/interfaces/dbus"
- "github.com/ubuntu-core/snappy/interfaces/seccomp"
- "github.com/ubuntu-core/snappy/interfaces/udev"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/apparmor"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/interfaces/dbus"
+ "github.com/snapcore/snapd/interfaces/seccomp"
+ "github.com/snapcore/snapd/interfaces/udev"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
)
func (m *InterfaceManager) initialize(extra []interfaces.Interface) error {
@@ -221,5 +222,13 @@
}
var securityBackends = []interfaces.SecurityBackend{
- &apparmor.Backend{}, &seccomp.Backend{}, &dbus.Backend{}, &udev.Backend{},
+ &seccomp.Backend{}, &dbus.Backend{}, &udev.Backend{},
+}
+
+func init() {
+ switch release.ReleaseInfo.ID {
+ case "ubuntu":
+ // Enable apparmor support when running on Ubuntu
+ securityBackends = append(securityBackends, &apparmor.Backend{})
+ }
}
diff -Nru snapd-2.0.5/overlord/ifacestate/ifacemgr.go snapd-2.0.8/overlord/ifacestate/ifacemgr.go
--- snapd-2.0.5/overlord/ifacestate/ifacemgr.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/ifacestate/ifacemgr.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,9 +24,9 @@
import (
"fmt"
- "github.com/ubuntu-core/snappy/i18n"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/i18n"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/overlord/state"
)
// InterfaceManager is responsible for the maintenance of interfaces in
diff -Nru snapd-2.0.5/overlord/ifacestate/ifacemgr_test.go snapd-2.0.8/overlord/ifacestate/ifacemgr_test.go
--- snapd-2.0.5/overlord/ifacestate/ifacemgr_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/ifacestate/ifacemgr_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,14 +24,13 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/overlord/ifacestate"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/snappy"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/overlord/ifacestate"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
)
func TestInterfaceManager(t *testing.T) { TestingT(t) }
@@ -212,7 +211,7 @@
}
func (s *interfaceManagerSuite) mockUpdatedSnap(c *C, yamlText string, revision int) *snap.Info {
- sideInfo := &snap.SideInfo{Revision: revision}
+ sideInfo := &snap.SideInfo{Revision: snap.R(revision)}
snapInfo := snaptest.MockSnap(c, yamlText, sideInfo)
s.state.Lock()
@@ -451,7 +450,10 @@
// Ensure that we have slots on the OS snap.
repo := mgr.Repository()
slots := repo.Slots(snapInfo.Name())
- c.Assert(slots, HasLen, 17)
+ // NOTE: This is not an exact test as it duplicates functionality elsewhere
+ // and is was a pain to update each time. This is correctly handled by the
+ // implicit slot tests in snap/implicit_test.go
+ c.Assert(len(slots) > 18, Equals, true)
}
func (s *interfaceManagerSuite) TestDoSetupSnapSecuirtyReloadsConnectionsWhenInvokedOnPlugSide(c *C) {
@@ -466,7 +468,7 @@
s.testDoSetupSnapSecuirtyReloadsConnectionsWhenInvokedOn(c, snapInfo.Name(), snapInfo.Revision)
}
-func (s *interfaceManagerSuite) testDoSetupSnapSecuirtyReloadsConnectionsWhenInvokedOn(c *C, snapName string, revision int) {
+func (s *interfaceManagerSuite) testDoSetupSnapSecuirtyReloadsConnectionsWhenInvokedOn(c *C, snapName string, revision snap.Revision) {
s.mockIface(c, &interfaces.TestInterface{InterfaceName: "test"})
s.state.Lock()
@@ -499,8 +501,8 @@
c.Check(slot.Connections[0], DeepEquals, interfaces.PlugRef{Snap: "consumer", Name: "plug"})
}
-// The setup-profiles task will honor snappy.DeveloperMode flag by storing it
-// in the SnapState.Flags (as DevMode) and by actually setting up security
+// The setup-profiles task will honor snapstate.DevMode flag by storing it
+// in the SnapState.Flags and by actually setting up security
// using that flag. Old copy of SnapState.Flag's DevMode is saved for the undo
// handler under `old-devmode`.
func (s *interfaceManagerSuite) TestSetupProfilesHonorsDevMode(c *C) {
@@ -513,7 +515,7 @@
// Run the setup-profiles task and let it finish.
// Note that the task will see SnapSetup.Flags equal to DeveloperMode.
change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{
- Name: snapInfo.Name(), Flags: int(snappy.DeveloperMode), Revision: snapInfo.Revision})
+ Name: snapInfo.Name(), Flags: snapstate.DevMode, Revision: snapInfo.Revision})
mgr.Ensure()
mgr.Wait()
mgr.Stop()
@@ -570,7 +572,7 @@
// Sanity check, the revisions are different.
c.Assert(oldSnapInfo.Revision, Not(Equals), 42)
- c.Assert(newSnapInfo.Revision, Equals, 42)
+ c.Assert(newSnapInfo.Revision, Equals, snap.R(42))
// Run the setup-profiles task for the new revision and let it finish.
change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{
@@ -602,7 +604,7 @@
//
// This variant checks restoring DevMode to true
func (s *interfaceManagerSuite) TestSetupProfilesUndoDevModeTrue(c *C) {
- s.undoDevModeCheck(c, snappy.InstallFlags(0), true)
+ s.undoDevModeCheck(c, 0, true)
}
// The undo handler of the setup-profiles task will honor `old-devmode` that
@@ -611,10 +613,10 @@
//
// This variant checks restoring DevMode to false
func (s *interfaceManagerSuite) TestSetupProfilesUndoDevModeFalse(c *C) {
- s.undoDevModeCheck(c, snappy.InstallFlags(0), false)
+ s.undoDevModeCheck(c, 0, false)
}
-func (s *interfaceManagerSuite) undoDevModeCheck(c *C, flags snappy.InstallFlags, devMode bool) {
+func (s *interfaceManagerSuite) undoDevModeCheck(c *C, flags snapstate.Flags, devMode bool) {
// Put the OS and sample snaps in place.
s.mockSnap(c, osSnapYaml)
snapInfo := s.mockSnap(c, sampleSnapYaml)
@@ -624,7 +626,10 @@
// Run the setup-profiles task in UndoMode and let it finish.
change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{
- Name: snapInfo.Name(), Flags: int(flags), Revision: snapInfo.Revision})
+ Name: snapInfo.Name(),
+ Flags: snapstate.SnapSetupFlags(flags),
+ Revision: snapInfo.Revision,
+ })
s.state.Lock()
task := change.Tasks()[0]
// Inject the old value of DevMode flag for the task handler to restore
diff -Nru snapd-2.0.5/overlord/overlord.go snapd-2.0.8/overlord/overlord.go
--- snapd-2.0.5/overlord/overlord.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/overlord.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,13 +28,13 @@
"gopkg.in/tomb.v2"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
- "github.com/ubuntu-core/snappy/overlord/assertstate"
- "github.com/ubuntu-core/snappy/overlord/ifacestate"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/assertstate"
+ "github.com/snapcore/snapd/overlord/ifacestate"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
)
var (
diff -Nru snapd-2.0.5/overlord/overlord_test.go snapd-2.0.8/overlord/overlord_test.go
--- snapd-2.0.5/overlord/overlord_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/overlord_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -30,11 +30,11 @@
. "gopkg.in/check.v1"
"gopkg.in/tomb.v2"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/testutil"
- "github.com/ubuntu-core/snappy/overlord"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord"
+ "github.com/snapcore/snapd/overlord/state"
)
func TestOverlord(t *testing.T) { TestingT(t) }
diff -Nru snapd-2.0.5/overlord/snapstate/backend/copydata.go snapd-2.0.8/overlord/snapstate/backend/copydata.go
--- snapd-2.0.5/overlord/snapstate/backend/copydata.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/backend/copydata.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,65 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package backend
+
+import (
+ "os"
+
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+)
+
+// CopySnapData makes a copy of oldSnap data for newSnap in its data directories.
+func (b Backend) CopySnapData(newSnap, oldSnap *snap.Info, meter progress.Meter) error {
+ // deal with the old data or
+ // otherwise just create a empty data dir
+
+ // Make sure the common data directory exists, even if this isn't a new
+ // install.
+ if err := os.MkdirAll(newSnap.CommonDataDir(), 0755); err != nil {
+ return err
+ }
+
+ if oldSnap == nil {
+ return os.MkdirAll(newSnap.DataDir(), 0755)
+ }
+
+ return copySnapData(oldSnap, newSnap)
+}
+
+// UndoCopySnapData removes the copy that may have been done for newInfo snap of oldInfo snap data and also the data directories that may have been created for newInfo snap.
+func (b Backend) UndoCopySnapData(newInfo *snap.Info, oldInfo *snap.Info, meter progress.Meter) error {
+ err1 := b.RemoveSnapData(newInfo)
+ if err1 != nil {
+ logger.Noticef("Cannot remove data directories for %q: %v", newInfo.Name(), err1)
+ }
+
+ var err2 error
+ if oldInfo == nil {
+ // first install, remove created common data dir
+ err2 = b.RemoveSnapCommonData(newInfo)
+ if err2 != nil {
+ logger.Noticef("Cannot remove common data directories for %q: %v", newInfo.Name(), err2)
+ }
+ }
+
+ return firstErr(err1, err2)
+}
diff -Nru snapd-2.0.5/overlord/snapstate/backend/copydata_test.go snapd-2.0.8/overlord/snapstate/backend/copydata_test.go
--- snapd-2.0.5/overlord/snapstate/backend/copydata_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/backend/copydata_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,376 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package backend_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "regexp"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+
+ "github.com/snapcore/snapd/overlord/snapstate/backend"
+)
+
+type copydataSuite struct {
+ be backend.Backend
+ nullProgress progress.NullProgress
+ tempdir string
+}
+
+var _ = Suite(©dataSuite{})
+
+func (s *copydataSuite) SetUpTest(c *C) {
+ s.tempdir = c.MkDir()
+ dirs.SetRootDir(s.tempdir)
+}
+
+func (s *copydataSuite) TearDownTest(c *C) {
+ dirs.SetRootDir("")
+}
+
+const (
+ helloYaml1 = `name: hello
+version: 1.0
+`
+ helloYaml2 = `name: hello
+version: 2.0
+`
+)
+
+func (s *copydataSuite) TestCopyData(c *C) {
+ homedir := filepath.Join(s.tempdir, "home", "user1", "snap")
+ homeData := filepath.Join(homedir, "hello/10")
+ err := os.MkdirAll(homeData, 0755)
+ c.Assert(err, IsNil)
+ homeCommonData := filepath.Join(homedir, "hello/common")
+ err = os.MkdirAll(homeCommonData, 0755)
+ c.Assert(err, IsNil)
+
+ canaryData := []byte("ni ni ni")
+
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+ // just creates data dirs in this case
+ err = s.be.CopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ canaryDataFile := filepath.Join(v1.DataDir(), "canary.txt")
+ err = ioutil.WriteFile(canaryDataFile, canaryData, 0644)
+ c.Assert(err, IsNil)
+ canaryDataFile = filepath.Join(v1.CommonDataDir(), "canary.common")
+ err = ioutil.WriteFile(canaryDataFile, canaryData, 0644)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(filepath.Join(homeData, "canary.home"), canaryData, 0644)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(filepath.Join(homeCommonData, "canary.common_home"), canaryData, 0644)
+ c.Assert(err, IsNil)
+
+ v2 := snaptest.MockSnap(c, helloYaml2, &snap.SideInfo{Revision: snap.R(20)})
+ err = s.be.CopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ newCanaryDataFile := filepath.Join(dirs.SnapDataDir, "hello/20", "canary.txt")
+ content, err := ioutil.ReadFile(newCanaryDataFile)
+ c.Assert(err, IsNil)
+ c.Assert(content, DeepEquals, canaryData)
+
+ // ensure common data file is still there (even though it didn't get copied)
+ newCanaryDataFile = filepath.Join(dirs.SnapDataDir, "hello", "common", "canary.common")
+ content, err = ioutil.ReadFile(newCanaryDataFile)
+ c.Assert(err, IsNil)
+ c.Assert(content, DeepEquals, canaryData)
+
+ newCanaryDataFile = filepath.Join(homedir, "hello/20", "canary.home")
+ content, err = ioutil.ReadFile(newCanaryDataFile)
+ c.Assert(err, IsNil)
+ c.Assert(content, DeepEquals, canaryData)
+
+ // ensure home common data file is still there (even though it didn't get copied)
+ newCanaryDataFile = filepath.Join(homedir, "hello", "common", "canary.common_home")
+ content, err = ioutil.ReadFile(newCanaryDataFile)
+ c.Assert(err, IsNil)
+ c.Assert(content, DeepEquals, canaryData)
+}
+
+// ensure that even with no home dir there is no error and the
+// system data gets copied
+func (s *copydataSuite) TestCopyDataNoUserHomes(c *C) {
+ // this home dir path does not exist
+ oldSnapDataHomeGlob := dirs.SnapDataHomeGlob
+ defer func() { dirs.SnapDataHomeGlob = oldSnapDataHomeGlob }()
+ dirs.SnapDataHomeGlob = filepath.Join(s.tempdir, "no-such-home", "*", "snap")
+
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+ err := s.be.CopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ canaryDataFile := filepath.Join(v1.DataDir(), "canary.txt")
+ err = ioutil.WriteFile(canaryDataFile, []byte(""), 0644)
+ c.Assert(err, IsNil)
+ canaryDataFile = filepath.Join(v1.CommonDataDir(), "canary.common")
+ err = ioutil.WriteFile(canaryDataFile, []byte(""), 0644)
+ c.Assert(err, IsNil)
+
+ v2 := snaptest.MockSnap(c, helloYaml2, &snap.SideInfo{Revision: snap.R(20)})
+ err = s.be.CopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ _, err = os.Stat(filepath.Join(v2.DataDir(), "canary.txt"))
+ c.Assert(err, IsNil)
+ _, err = os.Stat(filepath.Join(v2.CommonDataDir(), "canary.common"))
+ c.Assert(err, IsNil)
+
+ // sanity atm
+ c.Check(v1.DataDir(), Not(Equals), v2.DataDir())
+ c.Check(v1.CommonDataDir(), Equals, v2.CommonDataDir())
+}
+
+func (s *copydataSuite) populateData(c *C, revision snap.Revision) {
+ datadir := filepath.Join(dirs.SnapDataDir, "hello/"+revision.String())
+ subdir := filepath.Join(datadir, "random-subdir")
+ err := os.MkdirAll(subdir, 0755)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(filepath.Join(subdir, "canary"), nil, 0644)
+ c.Assert(err, IsNil)
+}
+
+func (s copydataSuite) populateHomeData(c *C, user string, revision snap.Revision) (homedir string) {
+ homedir = filepath.Join(s.tempdir, "home", user, "snap")
+ homeData := filepath.Join(homedir, "hello/"+revision.String())
+ err := os.MkdirAll(homeData, 0755)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(filepath.Join(homeData, "canary.home"), nil, 0644)
+ c.Assert(err, IsNil)
+ return
+}
+
+func (s *copydataSuite) TestCopyDataDoUndo(c *C) {
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+ s.populateData(c, snap.R(10))
+ homedir := s.populateHomeData(c, "user1", snap.R(10))
+
+ // pretend we install a new version
+ v2 := snaptest.MockSnap(c, helloYaml2, &snap.SideInfo{Revision: snap.R(20)})
+
+ // copy data
+ err := s.be.CopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+ v2data := filepath.Join(dirs.SnapDataDir, "hello/20")
+ l, err := filepath.Glob(filepath.Join(v2data, "*"))
+ c.Assert(err, IsNil)
+ c.Assert(l, HasLen, 1)
+ v2HomeData := filepath.Join(homedir, "hello/20")
+ l, err = filepath.Glob(filepath.Join(v2HomeData, "*"))
+ c.Assert(err, IsNil)
+ c.Assert(l, HasLen, 1)
+
+ err = s.be.UndoCopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ // now removed
+ _, err = os.Stat(v2data)
+ c.Assert(os.IsNotExist(err), Equals, true)
+ _, err = os.Stat(v2HomeData)
+ c.Assert(os.IsNotExist(err), Equals, true)
+}
+
+func (s *copydataSuite) TestCopyDataDoUndoNoUserHomes(c *C) {
+ // this home dir path does not exist
+ oldSnapDataHomeGlob := dirs.SnapDataHomeGlob
+ defer func() { dirs.SnapDataHomeGlob = oldSnapDataHomeGlob }()
+ dirs.SnapDataHomeGlob = filepath.Join(s.tempdir, "no-such-home", "*", "snap")
+
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+ s.populateData(c, snap.R(10))
+
+ // pretend we install a new version
+ v2 := snaptest.MockSnap(c, helloYaml2, &snap.SideInfo{Revision: snap.R(20)})
+
+ // copy data
+ err := s.be.CopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+ v2data := filepath.Join(dirs.SnapDataDir, "hello/20")
+ l, err := filepath.Glob(filepath.Join(v2data, "*"))
+ c.Assert(err, IsNil)
+ c.Assert(l, HasLen, 1)
+
+ err = s.be.UndoCopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ // now removed
+ _, err = os.Stat(v2data)
+ c.Assert(os.IsNotExist(err), Equals, true)
+}
+
+func (s *copydataSuite) TestCopyDataDoUndoFirstInstall(c *C) {
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+
+ // first install
+ err := s.be.CopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+ _, err = os.Stat(v1.DataDir())
+ c.Assert(err, IsNil)
+ _, err = os.Stat(v1.CommonDataDir())
+ c.Assert(err, IsNil)
+
+ err = s.be.UndoCopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+ _, err = os.Stat(v1.DataDir())
+ c.Check(os.IsNotExist(err), Equals, true)
+ _, err = os.Stat(v1.CommonDataDir())
+ c.Check(os.IsNotExist(err), Equals, true)
+}
+
+func (s *copydataSuite) TestCopyDataDoIdempotent(c *C) {
+ // make sure that a retry wouldn't stumble on partial work
+
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+
+ s.populateData(c, snap.R(10))
+ homedir := s.populateHomeData(c, "user1", snap.R(10))
+
+ // pretend we install a new version
+ v2 := snaptest.MockSnap(c, helloYaml2, &snap.SideInfo{Revision: snap.R(20)})
+
+ // copy data
+ err := s.be.CopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ err = s.be.CopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ v2data := filepath.Join(dirs.SnapDataDir, "hello/20")
+ l, err := filepath.Glob(filepath.Join(v2data, "*"))
+ c.Assert(err, IsNil)
+ c.Assert(l, HasLen, 1)
+ v2HomeData := filepath.Join(homedir, "hello/20")
+ l, err = filepath.Glob(filepath.Join(v2HomeData, "*"))
+ c.Assert(err, IsNil)
+ c.Assert(l, HasLen, 1)
+}
+
+func (s *copydataSuite) TestCopyDataUndoIdempotent(c *C) {
+ // make sure that a retry wouldn't stumble on partial work
+
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+ s.populateData(c, snap.R(10))
+ homedir := s.populateHomeData(c, "user1", snap.R(10))
+
+ // pretend we install a new version
+ v2 := snaptest.MockSnap(c, helloYaml2, &snap.SideInfo{Revision: snap.R(20)})
+
+ // copy data
+ err := s.be.CopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ v2data := filepath.Join(dirs.SnapDataDir, "hello/20")
+
+ err = s.be.UndoCopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ err = s.be.UndoCopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ // now removed
+ _, err = os.Stat(v2data)
+ c.Assert(os.IsNotExist(err), Equals, true)
+ v2HomeData := filepath.Join(homedir, "hello/20")
+ _, err = os.Stat(v2HomeData)
+ c.Assert(os.IsNotExist(err), Equals, true)
+}
+
+func (s *copydataSuite) TestCopyDataDoFirstInstallIdempotent(c *C) {
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+
+ // first install
+ err := s.be.CopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ err = s.be.CopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ _, err = os.Stat(v1.DataDir())
+ c.Assert(err, IsNil)
+ _, err = os.Stat(v1.CommonDataDir())
+ c.Assert(err, IsNil)
+
+ err = s.be.UndoCopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+ _, err = os.Stat(v1.DataDir())
+ c.Check(os.IsNotExist(err), Equals, true)
+ _, err = os.Stat(v1.CommonDataDir())
+ c.Check(os.IsNotExist(err), Equals, true)
+}
+
+func (s *copydataSuite) TestCopyDataUndoFirstInstallIdempotent(c *C) {
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+
+ // first install
+ err := s.be.CopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+ _, err = os.Stat(v1.DataDir())
+ c.Assert(err, IsNil)
+ _, err = os.Stat(v1.CommonDataDir())
+ c.Assert(err, IsNil)
+
+ err = s.be.UndoCopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ err = s.be.UndoCopySnapData(v1, nil, &s.nullProgress)
+ c.Assert(err, IsNil)
+
+ _, err = os.Stat(v1.DataDir())
+ c.Check(os.IsNotExist(err), Equals, true)
+ _, err = os.Stat(v1.CommonDataDir())
+ c.Check(os.IsNotExist(err), Equals, true)
+}
+
+func (s *copydataSuite) TestCopyDataCopyFailure(c *C) {
+ v1 := snaptest.MockSnap(c, helloYaml1, &snap.SideInfo{Revision: snap.R(10)})
+ s.populateData(c, snap.R(10))
+
+ // pretend we install a new version
+ v2 := snaptest.MockSnap(c, helloYaml2, &snap.SideInfo{Revision: snap.R(20)})
+
+ fakeBinDir := filepath.Join(s.tempdir, "bin")
+ err := os.MkdirAll(fakeBinDir, 0755)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(filepath.Join(fakeBinDir, "cp"), []byte(
+ `#!/bin/sh
+echo cp: boom
+exit 3
+`), 0755)
+ c.Assert(err, IsNil)
+
+ oldPATH := os.Getenv("PATH")
+ defer os.Setenv("PATH", oldPATH)
+ os.Setenv("PATH", fakeBinDir+":"+oldPATH)
+
+ // copy data will fail
+ err = s.be.CopySnapData(v2, v1, &s.nullProgress)
+ c.Assert(err, ErrorMatches, regexp.QuoteMeta(fmt.Sprintf("cannot copy %s to %s: cp: boom", v1.DataDir(), v2.DataDir())))
+}
diff -Nru snapd-2.0.5/overlord/snapstate/backend/link.go snapd-2.0.8/overlord/snapstate/backend/link.go
--- snapd-2.0.5/overlord/snapstate/backend/link.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/backend/link.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,12 +24,12 @@
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
// XXX: eventually not needed
- "github.com/ubuntu-core/snappy/snappy"
- "github.com/ubuntu-core/snappy/wrappers"
+ "github.com/snapcore/snapd/snappy"
+ "github.com/snapcore/snapd/wrappers"
)
func updateCurrentSymlinks(info *snap.Info) error {
diff -Nru snapd-2.0.5/overlord/snapstate/backend/link_test.go snapd-2.0.8/overlord/snapstate/backend/link_test.go
--- snapd-2.0.5/overlord/snapstate/backend/link_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/backend/link_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,14 +25,14 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/systemd"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/systemd"
- "github.com/ubuntu-core/snappy/overlord/snapstate/backend"
+ "github.com/snapcore/snapd/overlord/snapstate/backend"
)
func TestBackend(t *testing.T) { TestingT(t) }
@@ -62,6 +62,9 @@
func (s *linkSuite) TestLinkDoUndoGenerateWrappers(c *C) {
const yaml = `name: hello
version: 1.0
+environment:
+ KEY: value
+
apps:
bin:
command: bin
@@ -70,7 +73,7 @@
daemon: simple
`
- info := snaptest.MockSnap(c, yaml, &snap.SideInfo{Revision: 11})
+ info := snaptest.MockSnap(c, yaml, &snap.SideInfo{Revision: snap.R(11)})
err := s.be.LinkSnap(info)
c.Assert(err, IsNil)
@@ -99,7 +102,7 @@
version: 1.0
`
- info := snaptest.MockSnap(c, yaml, &snap.SideInfo{Revision: 11})
+ info := snaptest.MockSnap(c, yaml, &snap.SideInfo{Revision: snap.R(11)})
err := s.be.LinkSnap(info)
c.Assert(err, IsNil)
@@ -130,6 +133,8 @@
const yaml = `name: hello
version: 1.0
+environment:
+ KEY: value
apps:
bin:
command: bin
@@ -138,7 +143,7 @@
daemon: simple
`
- info := snaptest.MockSnap(c, yaml, &snap.SideInfo{Revision: 11})
+ info := snaptest.MockSnap(c, yaml, &snap.SideInfo{Revision: snap.R(11)})
err := s.be.LinkSnap(info)
c.Assert(err, IsNil)
@@ -166,7 +171,7 @@
c.Assert(currentDataDir, Equals, dataDir)
}
-func (s *linkSuite) TestLinkUnoIdempotent(c *C) {
+func (s *linkSuite) TestLinkUndoIdempotent(c *C) {
// make sure that a retry wouldn't stumble on partial work
const yaml = `name: hello
@@ -179,7 +184,7 @@
daemon: simple
`
- info := snaptest.MockSnap(c, yaml, &snap.SideInfo{Revision: 11})
+ info := snaptest.MockSnap(c, yaml, &snap.SideInfo{Revision: snap.R(11)})
err := s.be.LinkSnap(info)
c.Assert(err, IsNil)
diff -Nru snapd-2.0.5/overlord/snapstate/backend/snapdata.go snapd-2.0.8/overlord/snapstate/backend/snapdata.go
--- snapd-2.0.5/overlord/snapstate/backend/snapdata.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/backend/snapdata.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,127 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package backend
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+
+ "github.com/snapcore/snapd/snap"
+)
+
+// RemoveSnapData removes the data for the given version of the given snap.
+func (b Backend) RemoveSnapData(snap *snap.Info) error {
+ dirs, err := snapDataDirs(snap)
+ if err != nil {
+ return err
+ }
+
+ return removeDirs(dirs)
+}
+
+// RemoveSnapCommonData removes the data common between versions of the given snap.
+func (b Backend) RemoveSnapCommonData(snap *snap.Info) error {
+ dirs, err := snapCommonDataDirs(snap)
+ if err != nil {
+ return err
+ }
+
+ return removeDirs(dirs)
+}
+
+func removeDirs(dirs []string) error {
+ for _, dir := range dirs {
+ if err := os.RemoveAll(dir); err != nil {
+ return err
+ }
+
+ // Attempt to remove the parent directory as well (ignore any failure)
+ os.Remove(filepath.Dir(dir))
+ }
+
+ return nil
+}
+
+// snapDataDirs returns the list of data directories for the given snap version
+func snapDataDirs(snap *snap.Info) ([]string, error) {
+ // collect the directories, homes first
+ found, err := filepath.Glob(snap.DataHomeDir())
+ if err != nil {
+ return nil, err
+ }
+ // then system data
+ found = append(found, snap.DataDir())
+
+ return found, nil
+}
+
+// snapCommonDataDirs returns the list of data directories common between versions of the given snap
+func snapCommonDataDirs(snap *snap.Info) ([]string, error) {
+ // collect the directories, homes first
+ found, err := filepath.Glob(snap.CommonDataHomeDir())
+ if err != nil {
+ return nil, err
+ }
+ // then system data
+ found = append(found, snap.CommonDataDir())
+
+ return found, nil
+}
+
+// Copy all data for oldSnap to newSnap
+// (but never overwrite)
+func copySnapData(oldSnap, newSnap *snap.Info) (err error) {
+ oldDataDirs, err := snapDataDirs(oldSnap)
+ if err != nil {
+ return err
+ }
+
+ newSuffix := filepath.Base(newSnap.DataDir())
+ for _, oldDir := range oldDataDirs {
+ // replace the trailing "../$old-suffix" with the "../$new-suffix"
+ newDir := filepath.Join(filepath.Dir(oldDir), newSuffix)
+ if err := copySnapDataDirectory(oldDir, newDir); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Lowlevel copy the snap data (but never override existing data)
+func copySnapDataDirectory(oldPath, newPath string) (err error) {
+ if _, err := os.Stat(oldPath); err == nil {
+ if _, err := os.Stat(newPath); err != nil {
+ // there is no golang "CopyFile"
+ cmd := exec.Command("cp", "-a", oldPath, newPath)
+ if output, err := cmd.CombinedOutput(); err != nil {
+ output = bytes.TrimSpace(output)
+ if len(output) > 0 {
+ err = fmt.Errorf("%s", output)
+ }
+ return fmt.Errorf("cannot copy %s to %s: %v", oldPath, newPath, err)
+ }
+ }
+ }
+ return nil
+}
diff -Nru snapd-2.0.5/overlord/snapstate/backend.go snapd-2.0.8/overlord/snapstate/backend.go
--- snapd-2.0.5/overlord/snapstate/backend.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/backend.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,32 +20,41 @@
package snapstate
import (
- "github.com/ubuntu-core/snappy/overlord/snapstate/backend"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snappy"
- "github.com/ubuntu-core/snappy/store"
+ "github.com/snapcore/snapd/overlord/snapstate/backend"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snappy"
+ "github.com/snapcore/snapd/store"
)
+// A StoreService can find, list available updates and offer for download snaps.
+type StoreService interface {
+ Snap(string, string, store.Authenticator) (*snap.Info, error)
+ Find(string, string, store.Authenticator) ([]*snap.Info, error)
+ ListRefresh([]*store.RefreshCandidate, store.Authenticator) ([]*snap.Info, error)
+ SuggestedCurrency() string
+
+ Download(*snap.Info, progress.Meter, store.Authenticator) (string, error)
+}
+
type managerBackend interface {
// install releated
- Download(name, channel string, checker func(*snap.Info) error, meter progress.Meter, auther store.Authenticator) (*snap.Info, string, error)
- CheckSnap(snapFilePath string, curInfo *snap.Info, flags int) error
- SetupSnap(snapFilePath string, si *snap.SideInfo, flags int) error
- CopySnapData(newSnap, oldSnap *snap.Info, flags int) error
+ Download(name, channel string, checker func(*snap.Info) error, meter progress.Meter, store StoreService, auther store.Authenticator) (*snap.Info, string, error)
+ SetupSnap(snapFilePath string, si *snap.SideInfo) error
+ CopySnapData(newSnap, oldSnap *snap.Info, meter progress.Meter) error
LinkSnap(info *snap.Info) error
// the undoers for install
UndoSetupSnap(s snap.PlaceInfo) error
- UndoCopySnapData(newSnap *snap.Info, flags int) error
+ UndoCopySnapData(newSnap, oldSnap *snap.Info, meter progress.Meter) error
// remove releated
- CanRemove(info *snap.Info, active bool) bool
UnlinkSnap(info *snap.Info, meter progress.Meter) error
RemoveSnapFiles(s snap.PlaceInfo, meter progress.Meter) error
RemoveSnapData(info *snap.Info) error
RemoveSnapCommonData(info *snap.Info) error
// testing helpers
+ Current(cur *snap.Info)
Candidate(sideInfo *snap.SideInfo)
}
@@ -55,10 +64,10 @@
}
func (b *defaultBackend) Candidate(*snap.SideInfo) {}
+func (b *defaultBackend) Current(*snap.Info) {}
-func (b *defaultBackend) Download(name, channel string, checker func(*snap.Info) error, meter progress.Meter, auther store.Authenticator) (*snap.Info, string, error) {
- mStore := snappy.NewConfiguredUbuntuStoreSnapRepository()
- snap, err := mStore.Snap(name, channel, auther)
+func (b *defaultBackend) Download(name, channel string, checker func(*snap.Info) error, meter progress.Meter, stor StoreService, auther store.Authenticator) (*snap.Info, string, error) {
+ snap, err := stor.Snap(name, channel, auther)
if err != nil {
return nil, "", err
}
@@ -68,7 +77,7 @@
return nil, "", err
}
- downloadedSnapFile, err := mStore.Download(snap, meter, auther)
+ downloadedSnapFile, err := stor.Download(snap, meter, auther)
if err != nil {
return nil, "", err
}
@@ -76,46 +85,21 @@
return snap, downloadedSnapFile, nil
}
-func (b *defaultBackend) CheckSnap(snapFilePath string, curInfo *snap.Info, flags int) error {
- meter := &progress.NullProgress{}
- return snappy.CheckSnap(snapFilePath, curInfo, snappy.InstallFlags(flags), meter)
-}
-
-func (b *defaultBackend) SetupSnap(snapFilePath string, sideInfo *snap.SideInfo, flags int) error {
+func (b *defaultBackend) SetupSnap(snapFilePath string, sideInfo *snap.SideInfo) error {
meter := &progress.NullProgress{}
- _, err := snappy.SetupSnap(snapFilePath, sideInfo, snappy.InstallFlags(flags), meter)
+ // XXX: pass 0 for flags temporarely, until SetupSnap is moved over,
+ // anyway they aren't used atm, and probably we don't want to pass flags
+ // as before but more precise information
+ _, err := snappy.SetupSnap(snapFilePath, sideInfo, 0, meter)
return err
}
-func (b *defaultBackend) CopySnapData(newInfo, oldInfo *snap.Info, flags int) error {
- meter := &progress.NullProgress{}
- return snappy.CopyData(newInfo, oldInfo, snappy.InstallFlags(flags), meter)
-}
-
func (b *defaultBackend) UndoSetupSnap(s snap.PlaceInfo) error {
meter := &progress.NullProgress{}
snappy.UndoSetupSnap(s, meter)
return nil
}
-func (b *defaultBackend) UndoCopySnapData(newInfo *snap.Info, flags int) error {
- meter := &progress.NullProgress{}
- snappy.UndoCopyData(newInfo, snappy.InstallFlags(flags), meter)
- return nil
-}
-
-func (b *defaultBackend) CanRemove(info *snap.Info, active bool) bool {
- return snappy.CanRemove(info, active)
-}
-
func (b *defaultBackend) RemoveSnapFiles(s snap.PlaceInfo, meter progress.Meter) error {
return snappy.RemoveSnapFiles(s, meter)
}
-
-func (b *defaultBackend) RemoveSnapData(info *snap.Info) error {
- return snappy.RemoveSnapData(info)
-}
-
-func (b *defaultBackend) RemoveSnapCommonData(info *snap.Info) error {
- return snappy.RemoveSnapCommonData(info)
-}
diff -Nru snapd-2.0.5/overlord/snapstate/backend_test.go snapd-2.0.8/overlord/snapstate/backend_test.go
--- snapd-2.0.5/overlord/snapstate/backend_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/backend_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,12 +23,12 @@
"errors"
"strings"
- "github.com/ubuntu-core/snappy/overlord/auth"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/store"
+ "github.com/snapcore/snapd/overlord/auth"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/store"
)
type fakeOp struct {
@@ -36,9 +36,8 @@
macaroon string
name string
- revno int
+ revno snap.Revision
channel string
- flags int
active bool
sinfo snap.SideInfo
@@ -54,7 +53,7 @@
linkSnapFailTrigger string
}
-func (f *fakeSnappyBackend) Download(name, channel string, checker func(*snap.Info) error, p progress.Meter, auther store.Authenticator) (*snap.Info, string, error) {
+func (f *fakeSnappyBackend) Download(name, channel string, checker func(*snap.Info) error, p progress.Meter, stor snapstate.StoreService, auther store.Authenticator) (*snap.Info, string, error) {
p.Notify("download")
var macaroon string
if auther != nil {
@@ -69,9 +68,9 @@
p.SetTotal(float64(f.fakeTotalProgress))
p.Set(float64(f.fakeCurrentProgress))
- revno := 11
+ revno := snap.R(11)
if channel == "channel-for-7" {
- revno = 7
+ revno.N = 7
}
info := &snap.Info{
@@ -92,29 +91,28 @@
return info, "downloaded-snap-path", nil
}
-func (f *fakeSnappyBackend) CheckSnap(snapFilePath string, curInfo *snap.Info, flags int) error {
- cur := ""
- if curInfo != nil {
- cur = curInfo.MountDir()
+func (f *fakeSnappyBackend) OpenSnapFile(snapFilePath string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ op := fakeOp{
+ op: "open-snap-file",
+ name: snapFilePath,
}
- f.ops = append(f.ops, fakeOp{
- op: "check-snap",
- name: snapFilePath,
- old: cur,
- flags: flags,
- })
- return nil
+
+ if si != nil {
+ op.sinfo = *si
+ }
+
+ f.ops = append(f.ops, op)
+ return &snap.Info{Architectures: []string{"all"}}, nil, nil
}
-func (f *fakeSnappyBackend) SetupSnap(snapFilePath string, si *snap.SideInfo, flags int) error {
- revno := 0
+func (f *fakeSnappyBackend) SetupSnap(snapFilePath string, si *snap.SideInfo) error {
+ revno := snap.R(0)
if si != nil {
revno = si.Revision
}
f.ops = append(f.ops, fakeOp{
op: "setup-snap",
name: snapFilePath,
- flags: flags,
revno: revno,
})
return nil
@@ -122,19 +120,23 @@
func (f *fakeSnappyBackend) ReadInfo(name string, si *snap.SideInfo) (*snap.Info, error) {
// naive emulation for now, always works
- return &snap.Info{SuggestedName: name, SideInfo: *si}, nil
+ info := &snap.Info{SuggestedName: name, SideInfo: *si}
+ if name == "gadget" {
+ info.Type = snap.TypeGadget
+ }
+ return info, nil
}
-func (f *fakeSnappyBackend) CopySnapData(newInfo, oldInfo *snap.Info, flags int) error {
+func (f *fakeSnappyBackend) CopySnapData(newInfo, oldInfo *snap.Info, p progress.Meter) error {
+ p.Notify("copy-data")
old := ""
if oldInfo != nil {
old = oldInfo.MountDir()
}
f.ops = append(f.ops, fakeOp{
- op: "copy-data",
- name: newInfo.MountDir(),
- flags: flags,
- old: old,
+ op: "copy-data",
+ name: newInfo.MountDir(),
+ old: old,
})
return nil
}
@@ -163,23 +165,20 @@
return nil
}
-func (f *fakeSnappyBackend) UndoCopySnapData(newInfo *snap.Info, flags int) error {
+func (f *fakeSnappyBackend) UndoCopySnapData(newInfo *snap.Info, oldInfo *snap.Info, p progress.Meter) error {
+ p.Notify("undo-copy-data")
+ old := ""
+ if oldInfo != nil {
+ old = oldInfo.MountDir()
+ }
f.ops = append(f.ops, fakeOp{
op: "undo-copy-snap-data",
name: newInfo.MountDir(),
+ old: old,
})
return nil
}
-func (f *fakeSnappyBackend) CanRemove(info *snap.Info, active bool) bool {
- f.ops = append(f.ops, fakeOp{
- op: "can-remove",
- name: info.MountDir(),
- active: active,
- })
- return true
-}
-
func (f *fakeSnappyBackend) UnlinkSnap(info *snap.Info, meter progress.Meter) error {
meter.Notify("unlink")
f.ops = append(f.ops, fakeOp{
@@ -225,6 +224,17 @@
})
}
+func (f *fakeSnappyBackend) Current(curInfo *snap.Info) {
+ old := ""
+ if curInfo != nil {
+ old = curInfo.MountDir()
+ }
+ f.ops = append(f.ops, fakeOp{
+ op: "current",
+ old: old,
+ })
+}
+
func (f *fakeSnappyBackend) ForeignTask(kind string, status state.Status, ss *snapstate.SnapSetup) {
f.ops = append(f.ops, fakeOp{
op: kind + ":" + status.String(),
diff -Nru snapd-2.0.5/overlord/snapstate/check_snap.go snapd-2.0.8/overlord/snapstate/check_snap.go
--- snapd-2.0.5/overlord/snapstate/check_snap.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/check_snap.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,110 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snapstate
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
+)
+
+// featureSet contains the flag values that can be listed in assumes entries
+// that this ubuntu-core actually provides.
+var featureSet = map[string]bool{
+ // Support for common data directory across revisions of a snap.
+ "common-data-dir": true,
+}
+
+func checkAssumes(s *snap.Info) error {
+ missing := ([]string)(nil)
+ for _, flag := range s.Assumes {
+ if !featureSet[flag] {
+ missing = append(missing, flag)
+ }
+ }
+ if len(missing) > 0 {
+ return fmt.Errorf("snap %q assumes unsupported features: %s (try new ubuntu-core)", s.Name(), strings.Join(missing, ", "))
+ }
+ return nil
+}
+
+// openSnapFile opens a snap blob returning both a snap.Info completed
+// with sideInfo (if not nil) and a corresponding snap.Container.
+func openSnapFileImpl(snapPath string, sideInfo *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ snapf, err := snap.Open(snapPath)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ info, err := snap.ReadInfoFromSnapFile(snapf, sideInfo)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return info, snapf, nil
+}
+
+var openSnapFile = openSnapFileImpl
+
+// checkSnap ensures that the snap can be installed.
+func checkSnap(state *state.State, snapFilePath string, curInfo *snap.Info, flags Flags) error {
+ // XXX: actually verify snap before using content from it unless dev-mode
+
+ s, _, err := openSnapFile(snapFilePath, nil)
+ if err != nil {
+ return err
+ }
+
+ // verify we have a valid architecture
+ if !arch.IsSupportedArchitecture(s.Architectures) {
+ return fmt.Errorf("snap %q supported architectures (%s) are incompatible with this system (%s)", s.Name(), strings.Join(s.Architectures, ", "), arch.UbuntuArchitecture())
+ }
+
+ // check assumes
+ err = checkAssumes(s)
+ if err != nil {
+ return err
+ }
+
+ if s.Type != snap.TypeGadget {
+ return nil
+ }
+ state.Lock()
+ defer state.Unlock()
+
+ if currentGadget, err := GadgetInfo(state); err == nil {
+ // TODO: actually compare snap ids, from current gadget and candidate
+ if currentGadget.Name() == s.Name() {
+ return nil
+ }
+
+ return fmt.Errorf("cannot replace gadget snap with a different one")
+ } else if release.OnClassic {
+ // for the time being
+ return fmt.Errorf("cannot install a gadget snap on classic")
+ }
+
+ // there should always be a gadget snap on devices
+ return fmt.Errorf("cannot find original gadget snap")
+}
diff -Nru snapd-2.0.5/overlord/snapstate/check_snap_test.go snapd-2.0.8/overlord/snapstate/check_snap_test.go
--- snapd-2.0.5/overlord/snapstate/check_snap_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/check_snap_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,283 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snapstate_test
+
+import (
+ "fmt"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/snap/squashfs"
+
+ "github.com/snapcore/snapd/overlord/snapstate"
+)
+
+type checkSnapSuite struct{}
+
+var _ = Suite(&checkSnapSuite{})
+
+func (s *checkSnapSuite) SetUpTest(c *C) {
+ dirs.SetRootDir(c.MkDir())
+}
+
+func (s *checkSnapSuite) TearDownTest(c *C) {
+ dirs.SetRootDir("")
+}
+
+func (s *checkSnapSuite) TestOpenSnapFile(c *C) {
+ const yaml = `name: hello
+version: 1.0
+apps:
+ bin:
+ command: bin
+`
+
+ snapPath := makeTestSnap(c, yaml)
+ info, snapf, err := snapstate.OpenSnapFileImpl(snapPath, nil)
+ c.Assert(err, IsNil)
+
+ c.Assert(snapf, FitsTypeOf, &squashfs.Snap{})
+ c.Check(info.Name(), Equals, "hello")
+}
+
+func (s *checkSnapSuite) TestOpenSnapFilebSideInfo(c *C) {
+ const yaml = `name: foo
+apps:
+ bar:
+ command: bin/bar
+plugs:
+ plug:
+slots:
+ slot:
+`
+
+ snapPath := makeTestSnap(c, yaml)
+ si := snap.SideInfo{OfficialName: "blessed", Revision: snap.R(42)}
+ info, _, err := snapstate.OpenSnapFileImpl(snapPath, &si)
+ c.Assert(err, IsNil)
+
+ // check side info
+ c.Check(info.Name(), Equals, "blessed")
+ c.Check(info.Revision, Equals, snap.R(42))
+
+ c.Check(info.SideInfo, DeepEquals, si)
+
+ // ensure that all leaf objects link back to the same snap.Info
+ // and not to some copy.
+ // (we had a bug around this)
+ c.Check(info.Apps["bar"].Snap, Equals, info)
+ c.Check(info.Plugs["plug"].Snap, Equals, info)
+ c.Check(info.Slots["slot"].Snap, Equals, info)
+
+}
+
+func (s *checkSnapSuite) TestCheckSnapErrorOnUnsupportedArchitecture(c *C) {
+ const yaml = `name: hello
+version: 1.10
+architectures:
+ - yadayada
+ - blahblah
+`
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ c.Check(path, Equals, "snap-path")
+ c.Check(si, IsNil)
+ return info, nil, nil
+ }
+ restore := snapstate.MockOpenSnapFile(openSnapFile)
+ defer restore()
+
+ err = snapstate.CheckSnap(nil, "snap-path", nil, 0)
+
+ errorMsg := fmt.Sprintf(`snap "hello" supported architectures (yadayada, blahblah) are incompatible with this system (%s)`, arch.UbuntuArchitecture())
+ c.Assert(err.Error(), Equals, errorMsg)
+}
+
+func (s *checkSnapSuite) TestCheckSnapInstallMissingAssumes(c *C) {
+ const yaml = `name: foo
+version: 1.0
+assumes: [f1, f2]`
+
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ return info, nil, nil
+ }
+ restore := snapstate.MockOpenSnapFile(openSnapFile)
+ defer restore()
+
+ err = snapstate.CheckSnap(nil, "snap-path", nil, 0)
+ c.Check(err, ErrorMatches, `snap "foo" assumes unsupported features: f1, f2.*`)
+}
+
+func (s *checkSnapSuite) TestCheckSnapInstallProvidedAssumes(c *C) {
+ const yaml = `name: foo
+version: 1.0
+assumes: [common-data-dir]`
+
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ return info, nil, nil
+ }
+ restore := snapstate.MockOpenSnapFile(openSnapFile)
+ defer restore()
+
+ err = snapstate.CheckSnap(nil, "snap-path", nil, 0)
+ c.Check(err, IsNil)
+}
+
+func (s *checkSnapSuite) TestCheckSnapGadgetUpdate(c *C) {
+ st := state.New(nil)
+ st.Lock()
+ defer st.Unlock()
+
+ si := &snap.SideInfo{Revision: snap.R(2)}
+ snaptest.MockSnap(c, `
+name: gadget
+type: gadget
+version: 1
+`, si)
+ snapstate.Set(st, "gadget", &snapstate.SnapState{
+ Active: true,
+ Sequence: []*snap.SideInfo{si},
+ })
+
+ const yaml = `name: gadget
+type: gadget
+version: 2
+`
+
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ return info, nil, nil
+ }
+ restore := snapstate.MockOpenSnapFile(openSnapFile)
+ defer restore()
+
+ st.Unlock()
+ err = snapstate.CheckSnap(st, "snap-path", nil, 0)
+ st.Lock()
+ c.Check(err, IsNil)
+}
+
+func (s *checkSnapSuite) TestCheckSnapGadgetAdditionProhibited(c *C) {
+ st := state.New(nil)
+ st.Lock()
+ defer st.Unlock()
+
+ si := &snap.SideInfo{Revision: snap.R(2)}
+ snaptest.MockSnap(c, `
+name: gadget
+type: gadget
+version: 1
+`, si)
+ snapstate.Set(st, "gadget", &snapstate.SnapState{
+ Active: true,
+ Sequence: []*snap.SideInfo{si},
+ })
+
+ const yaml = `name: zgadget
+type: gadget
+version: 2
+`
+
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ return info, nil, nil
+ }
+ restore := snapstate.MockOpenSnapFile(openSnapFile)
+ defer restore()
+
+ st.Unlock()
+ err = snapstate.CheckSnap(st, "snap-path", nil, 0)
+ st.Lock()
+ c.Check(err, ErrorMatches, "cannot replace gadget snap with a different one")
+}
+
+func (s *checkSnapSuite) TestCheckSnapGadgetMissingPrior(c *C) {
+ reset := release.MockOnClassic(false)
+ defer reset()
+
+ st := state.New(nil)
+ st.Lock()
+ defer st.Unlock()
+
+ const yaml = `name: gadget
+type: gadget
+version: 1
+`
+
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ return info, nil, nil
+ }
+ restore := snapstate.MockOpenSnapFile(openSnapFile)
+ defer restore()
+
+ st.Unlock()
+ err = snapstate.CheckSnap(st, "snap-path", nil, 0)
+ st.Lock()
+ c.Check(err, ErrorMatches, "cannot find original gadget snap")
+}
+
+func (s *checkSnapSuite) TestCheckSnapGadgetCannotBeInstalledOnClassic(c *C) {
+ reset := release.MockOnClassic(true)
+ defer reset()
+
+ st := state.New(nil)
+ st.Lock()
+ defer st.Unlock()
+
+ const yaml = `name: gadget
+type: gadget
+version: 1
+`
+
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
+ return info, nil, nil
+ }
+ restore := snapstate.MockOpenSnapFile(openSnapFile)
+ defer restore()
+
+ st.Unlock()
+ err = snapstate.CheckSnap(st, "snap-path", nil, 0)
+ st.Lock()
+ c.Check(err, ErrorMatches, "cannot install a gadget snap on classic")
+}
diff -Nru snapd-2.0.5/overlord/snapstate/export_test.go snapd-2.0.8/overlord/snapstate/export_test.go
--- snapd-2.0.5/overlord/snapstate/export_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/export_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,8 +24,8 @@
"gopkg.in/tomb.v2"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snap"
)
type ManagerBackend managerBackend
@@ -34,10 +34,6 @@
s.backend = b
}
-func SetSnapstateBackend(b ManagerBackend) {
- be = b
-}
-
type ForeignTaskTracker interface {
ForeignTask(kind string, status state.Status, ss *SnapSetup)
}
@@ -70,7 +66,25 @@
m.runner.AddHandler("error-trigger", erroringHandler, nil)
}
-func MockReadInfo(mock func(name string, si *snap.SideInfo) (*snap.Info, error)) func() {
+func MockReadInfo(mock func(name string, si *snap.SideInfo) (*snap.Info, error)) (restore func()) {
readInfo = mock
return func() { readInfo = snap.ReadInfo }
}
+
+var OpenSnapFileImpl = openSnapFileImpl
+
+func MockOpenSnapFile(mock func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error)) (restore func()) {
+ openSnapFile = mock
+ return func() { openSnapFile = openSnapFileImpl }
+}
+
+var (
+ CheckSnap = checkSnap
+ CanRemove = canRemove
+)
+
+// flagscompat
+const (
+ InterimUnusableFlagValueMin = interimUnusableLegacyFlagValueMin
+ InterimUnusableFlagValueLast = interimUnusableLegacyFlagValueLast
+)
diff -Nru snapd-2.0.5/overlord/snapstate/flagscompat_test.go snapd-2.0.8/overlord/snapstate/flagscompat_test.go
--- snapd-2.0.5/overlord/snapstate/flagscompat_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/flagscompat_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,157 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snapstate_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snappy"
+)
+
+type flagscompatSuite struct{}
+
+var _ = Suite(&flagscompatSuite{})
+
+const (
+ // copy here of the legacy values for when we drop snappy
+
+ snappyAllowUnauthenticated = 1 << iota
+ snappyInhibitHooks
+ snappyDoInstallGC
+ snappyAllowGadget
+
+ snappyDeveloperMode
+ snappyTryMode
+)
+
+// this is the minimum value larger than all the legacy/interim flags
+// combinations, so also at the same time the first flag value usable
+// again
+const interimUnusableFlagValueTop = snapstate.InterimUnusableFlagValueLast << 1
+
+func (s *flagscompatSuite) TestCopiedConstsSanity(c *C) {
+ // have this sanity test at the start at least, can be dropped
+ // when we drop snappy
+ c.Check(snappy.LegacyInstallFlags(snappyAllowUnauthenticated), Equals, snappy.LegacyAllowUnauthenticated)
+ c.Check(snappy.LegacyInstallFlags(snappyInhibitHooks), Equals, snappy.LegacyInhibitHooks)
+ c.Check(snappy.LegacyInstallFlags(snappyDoInstallGC), Equals, snappy.LegacyDoInstallGC)
+ c.Check(snappy.LegacyInstallFlags(snappyAllowGadget), Equals, snappy.LegacyAllowGadget)
+
+}
+
+func (s *flagscompatSuite) TestSnapSetupNewValuesUnchanged(c *C) {
+ // test that new snapstate flags based SnapSetup.Flags is
+ // unmarshalled as is
+
+ st := state.New(nil)
+ st.Lock()
+ defer st.Unlock()
+
+ t := st.NewTask("t", "...")
+
+ values := []int{
+ snapstate.DevMode,
+ snapstate.TryMode,
+ snapstate.DevMode | snapstate.TryMode,
+ interimUnusableFlagValueTop,
+ interimUnusableFlagValueTop | snapstate.DevMode,
+ interimUnusableFlagValueTop<<1 | snapstate.TryMode,
+ interimUnusableFlagValueTop << 4,
+ }
+
+ for _, f := range values {
+
+ t.Set("ss", snapstate.SnapSetup{
+ Flags: snapstate.SnapSetupFlags(f),
+ })
+
+ var ss snapstate.SnapSetup
+ err := t.Get("ss", &ss)
+ c.Assert(err, IsNil)
+
+ c.Check(ss.Flags, Equals, snapstate.SnapSetupFlags(f))
+ }
+
+}
+
+func (s *flagscompatSuite) TestRangeCapturesLegacyInterim(c *C) {
+ // double check that the reserved unusable flag range
+ // captures (aka contains) the old legacy/interim flags
+ // to protect them correctly
+
+ values := []int{
+ // these overlap but weren't used in snapd actually
+ //snappyAllowUnauthenticated,
+ //snappyInhibitHooks,
+ snappyDoInstallGC,
+ snappyAllowGadget,
+ snappyDeveloperMode,
+ snappyTryMode,
+ }
+
+ for _, v := range values {
+ c.Check(v < int(interimUnusableFlagValueTop), Equals, true)
+ c.Check(v >= int(snapstate.InterimUnusableFlagValueMin), Equals, true)
+ }
+
+ c.Check(snappyDoInstallGC, Equals, snapstate.InterimUnusableFlagValueMin)
+ c.Check(snappyTryMode, Equals, snapstate.InterimUnusableFlagValueLast)
+
+}
+
+func (s *flagscompatSuite) TestSnapSetupInterimValuesUpgrade(c *C) {
+ // test that the old snappy.* flags based SnapSetup.Flags
+ // are updated correctly to the new snapstate single shared flag set
+
+ st := state.New(nil)
+ st.Lock()
+ defer st.Unlock()
+
+ t := st.NewTask("t", "...")
+
+ tests := []struct {
+ interim, new int
+ }{
+ {snappyDeveloperMode, snapstate.DevMode},
+ {snappyTryMode, snapstate.TryMode},
+ {snappyDeveloperMode | snappyTryMode, snapstate.DevMode | snapstate.TryMode},
+ {snappyDeveloperMode | snappyDoInstallGC, snapstate.DevMode},
+ {snappyTryMode | snappyDoInstallGC, snapstate.TryMode},
+ {snappyDeveloperMode | snappyTryMode | snappyDoInstallGC, snapstate.DevMode | snapstate.TryMode},
+ {snappyDoInstallGC, 0},
+ {interimUnusableFlagValueTop - 1, snapstate.DevMode | snapstate.TryMode},
+ }
+
+ for _, tst := range tests {
+
+ t.Set("ss", snapstate.SnapSetup{
+ Flags: snapstate.SnapSetupFlags(tst.interim),
+ })
+
+ var ss snapstate.SnapSetup
+ err := t.Get("ss", &ss)
+ c.Assert(err, IsNil)
+
+ c.Check(ss.Flags, Equals, snapstate.SnapSetupFlags(tst.new))
+ }
+
+}
diff -Nru snapd-2.0.5/overlord/snapstate/link_snap_test.go snapd-2.0.8/overlord/snapstate/link_snap_test.go
--- snapd-2.0.5/overlord/snapstate/link_snap_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/link_snap_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,181 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snapstate_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snap"
+)
+
+type linkSnapSuite struct {
+ state *state.State
+ snapmgr *snapstate.SnapManager
+
+ fakeBackend *fakeSnappyBackend
+
+ reset func()
+}
+
+var _ = Suite(&linkSnapSuite{})
+
+func (s *linkSnapSuite) SetUpTest(c *C) {
+ s.fakeBackend = &fakeSnappyBackend{}
+ s.state = state.New(nil)
+
+ var err error
+ s.snapmgr, err = snapstate.Manager(s.state)
+ c.Assert(err, IsNil)
+ s.snapmgr.AddForeignTaskHandlers(s.fakeBackend)
+
+ snapstate.SetSnapManagerBackend(s.snapmgr, s.fakeBackend)
+
+ s.reset = snapstate.MockReadInfo(s.fakeBackend.ReadInfo)
+}
+
+func (s *linkSnapSuite) TearDownTest(c *C) {
+ s.reset()
+}
+
+func (s *linkSnapSuite) TestDoLinkSnapSuccess(c *C) {
+ s.state.Lock()
+ snapstate.Set(s.state, "foo", &snapstate.SnapState{
+ Candidate: &snap.SideInfo{
+ OfficialName: "foo",
+ Revision: snap.R(33),
+ },
+ })
+ t := s.state.NewTask("link-snap", "test")
+ t.Set("snap-setup", &snapstate.SnapSetup{
+ Name: "foo",
+ Channel: "beta",
+ })
+ s.state.NewChange("dummy", "...").AddTask(t)
+
+ s.state.Unlock()
+
+ s.snapmgr.Ensure()
+ s.snapmgr.Wait()
+
+ s.state.Lock()
+ defer s.state.Unlock()
+ var snapst snapstate.SnapState
+ err := snapstate.Get(s.state, "foo", &snapst)
+ c.Assert(err, IsNil)
+ c.Check(snapst.Active, Equals, true)
+ c.Check(snapst.Sequence, HasLen, 1)
+ c.Check(snapst.Candidate, IsNil)
+ c.Check(snapst.Channel, Equals, "beta")
+ c.Check(t.Status(), Equals, state.DoneStatus)
+}
+
+func (s *linkSnapSuite) TestDoUndoLinkSnap(c *C) {
+ s.state.Lock()
+ defer s.state.Unlock()
+ si := &snap.SideInfo{
+ OfficialName: "foo",
+ Revision: snap.R(33),
+ }
+ snapstate.Set(s.state, "foo", &snapstate.SnapState{
+ Candidate: si,
+ })
+ t := s.state.NewTask("link-snap", "test")
+ t.Set("snap-setup", &snapstate.SnapSetup{
+ Name: "foo",
+ Channel: "beta",
+ })
+ chg := s.state.NewChange("dummy", "...")
+ chg.AddTask(t)
+
+ terr := s.state.NewTask("error-trigger", "provoking total undo")
+ terr.WaitFor(t)
+ chg.AddTask(terr)
+
+ s.state.Unlock()
+
+ for i := 0; i < 3; i++ {
+ s.snapmgr.Ensure()
+ s.snapmgr.Wait()
+ }
+
+ s.state.Lock()
+ var snapst snapstate.SnapState
+ err := snapstate.Get(s.state, "foo", &snapst)
+ c.Assert(err, IsNil)
+ c.Check(snapst.Active, Equals, false)
+ c.Check(snapst.Sequence, HasLen, 0)
+ c.Check(snapst.Candidate, DeepEquals, si)
+ c.Check(snapst.Channel, Equals, "")
+ c.Check(t.Status(), Equals, state.UndoneStatus)
+}
+
+func (s *linkSnapSuite) TestDoLinkSnapTryToCleanupOnError(c *C) {
+ s.state.Lock()
+ defer s.state.Unlock()
+ si := &snap.SideInfo{
+ OfficialName: "foo",
+ Revision: snap.R(35),
+ }
+ snapstate.Set(s.state, "foo", &snapstate.SnapState{
+ Candidate: si,
+ })
+ t := s.state.NewTask("link-snap", "test")
+ t.Set("snap-setup", &snapstate.SnapSetup{
+ Name: "foo",
+ Channel: "beta",
+ })
+
+ s.fakeBackend.linkSnapFailTrigger = "/snap/foo/35"
+ s.state.NewChange("dummy", "...").AddTask(t)
+ s.state.Unlock()
+
+ s.snapmgr.Ensure()
+ s.snapmgr.Wait()
+
+ s.state.Lock()
+
+ // state as expected
+ var snapst snapstate.SnapState
+ err := snapstate.Get(s.state, "foo", &snapst)
+ c.Assert(err, IsNil)
+ c.Check(snapst.Active, Equals, false)
+ c.Check(snapst.Sequence, HasLen, 0)
+ c.Check(snapst.Candidate, DeepEquals, si)
+ c.Check(snapst.Channel, Equals, "")
+ c.Check(t.Status(), Equals, state.ErrorStatus)
+
+ // tried to cleanup
+ c.Check(s.fakeBackend.ops, DeepEquals, []fakeOp{
+ {
+ op: "candidate",
+ sinfo: *si,
+ },
+ {
+ op: "link-snap.failed",
+ name: "/snap/foo/35",
+ },
+ {
+ op: "unlink-snap",
+ name: "/snap/foo/35",
+ },
+ })
+}
diff -Nru snapd-2.0.5/overlord/snapstate/progress.go snapd-2.0.8/overlord/snapstate/progress.go
--- snapd-2.0.5/overlord/snapstate/progress.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/progress.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package snapstate
import (
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/state"
)
// TaskProgressAdapter adapts the progress.Meter to the task progress
diff -Nru snapd-2.0.5/overlord/snapstate/progress_test.go snapd-2.0.8/overlord/snapstate/progress_test.go
--- snapd-2.0.5/overlord/snapstate/progress_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/progress_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package snapstate
import (
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/state"
. "gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/overlord/snapstate/snapmgr.go snapd-2.0.8/overlord/snapstate/snapmgr.go
--- snapd-2.0.5/overlord/snapstate/snapmgr.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/snapmgr.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,32 +22,59 @@
import (
"fmt"
+ "os"
+ "strconv"
"gopkg.in/tomb.v2"
- "github.com/ubuntu-core/snappy/overlord/auth"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snappy"
- "github.com/ubuntu-core/snappy/store"
+ "github.com/snapcore/snapd/overlord/auth"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/store"
)
// SnapManager is responsible for the installation and removal of snaps.
type SnapManager struct {
state *state.State
backend managerBackend
+ store StoreService
runner *state.TaskRunner
}
+// SnapSetupFlags are flags stored in SnapSetup to control snap manager tasks.
+type SnapSetupFlags Flags
+
+// backward compatibility: upgrade old flags based on snappy.* flags values
+// to Flags if needed
+// XXX: this can be dropped and potentially the type at the earliest
+// in 2.0.9 (after being out for about two prune cycles), at the
+// latest when we need to recover the reserved unusable flag values,
+// or this gets annoying for other reasons
+func (ssfl *SnapSetupFlags) UnmarshalJSON(b []byte) error {
+ f, err := strconv.Atoi(string(b))
+ if err != nil {
+ return fmt.Errorf("invalid snap-setup flags: %v", err)
+ }
+ if f >= interimUnusableLegacyFlagValueMin && f < (interimUnusableLegacyFlagValueLast<<1) {
+ // snappy.DeveloperMode was 0x10, TryMode was 0x20,
+ // snapstate values are 1 and 2 so this does what we need
+ f >>= 4
+ }
+
+ *ssfl = SnapSetupFlags(f)
+
+ return nil
+}
+
// SnapSetup holds the necessary snap details to perform most snap manager tasks.
type SnapSetup struct {
- Name string `json:"name"`
- Revision int `json:"revision,omitempty"`
- Channel string `json:"channel,omitempty"`
- UserID int `json:"user-id,omitempty"`
+ Name string `json:"name"`
+ Revision snap.Revision `json:"revision,omitempty"`
+ Channel string `json:"channel,omitempty"`
+ UserID int `json:"user-id,omitempty"`
- Flags int `json:"flags,omitempty"`
+ Flags SnapSetupFlags `json:"flags,omitempty"`
SnapPath string `json:"snap-path,omitempty"`
}
@@ -60,17 +87,18 @@
return snap.MountDir(ss.Name, ss.Revision)
}
+// DevMode returns true if the snap is being installed in developer mode.
func (ss *SnapSetup) DevMode() bool {
- return ss.Flags&int(snappy.DeveloperMode) != 0
+ return ss.Flags&DevMode != 0
}
-// SnapStateFlags are flags stored in SnapState.
-type SnapStateFlags int
+// TryMode returns true if the snap is being installed in try mode directly from a directory.
+func (ss *SnapSetup) TryMode() bool {
+ return ss.Flags&TryMode != 0
+}
-const (
- // DevMode switches confinement to non-enforcing mode.
- DevMode = 1 << iota
-)
+// SnapStateFlags are flags stored in SnapState.
+type SnapStateFlags Flags
// SnapState holds the state for a snap installed in the system.
type SnapState struct {
@@ -80,7 +108,7 @@
Channel string `json:"channel,omitempty"`
Flags SnapStateFlags `json:"flags,omitempty"`
// incremented revision used for local installs
- LocalRevision int `json:"local-revision,omitempty"`
+ LocalRevision snap.Revision `json:"local-revision,omitempty"`
}
// Current returns the side info for the current revision in the snap revision sequence if there is one.
@@ -97,13 +125,48 @@
return snapst.Flags&DevMode != 0
}
+// SetDevMode sets/clears the DevMode flag in the SnapState.
+func (snapst *SnapState) SetDevMode(active bool) {
+ if active {
+ snapst.Flags |= DevMode
+ } else {
+ snapst.Flags &= ^DevMode
+ }
+}
+
+// TryMode returns true if the snap is installed in `try` mode as an
+// unpacked directory.
+func (snapst *SnapState) TryMode() bool {
+ return snapst.Flags&TryMode != 0
+}
+
+// SetTryMode sets/clears the TryMode flag in the SnapState.
+func (snapst *SnapState) SetTryMode(active bool) {
+ if active {
+ snapst.Flags |= TryMode
+ } else {
+ snapst.Flags &= ^TryMode
+ }
+}
+
// Manager returns a new snap manager.
func Manager(s *state.State) (*SnapManager, error) {
runner := state.NewTaskRunner(s)
backend := &defaultBackend{}
+
+ storeID := ""
+ // TODO: set the store-id here from the model information
+ if cand := os.Getenv("UBUNTU_STORE_ID"); cand != "" {
+ storeID = cand
+ }
+ store := store.NewUbuntuStoreSnapRepository(nil, storeID)
+ // TODO: if needed we could also put the store on the state using
+ // the Cache mechanism and an accessor function
+
m := &SnapManager{
state: s,
backend: backend,
+ store: store,
runner: runner,
}
@@ -112,7 +175,7 @@
return nil
}, nil)
- // install/update releated
+ // install/update related
runner.AddHandler("prepare-snap", m.doPrepareSnap, m.undoPrepareSnap)
runner.AddHandler("download-snap", m.doDownloadSnap, m.undoPrepareSnap)
runner.AddHandler("mount-snap", m.doMountSnap, m.undoMountSnap)
@@ -122,7 +185,7 @@
// FIXME: port to native tasks and rename
//runner.AddHandler("garbage-collect", m.doGarbageCollect, nil)
- // remove releated
+ // remove related
runner.AddHandler("unlink-snap", m.doUnlinkSnap, nil)
runner.AddHandler("clear-snap", m.doClearSnapData, nil)
runner.AddHandler("discard-snap", m.doDiscardSnap, nil)
@@ -138,17 +201,25 @@
return m, nil
}
-func checkRevisionIsNew(name string, snapst *SnapState, revision int) error {
+// Store returns the store service used by the manager.
+func (m *SnapManager) Store() StoreService {
+ return m.store
+}
+
+// ReplaceStore replaces the store used by manager.
+func (m *SnapManager) ReplaceStore(store StoreService) {
+ m.store = store
+}
+
+func checkRevisionIsNew(name string, snapst *SnapState, revision snap.Revision) error {
for _, si := range snapst.Sequence {
if si.Revision == revision {
- return fmt.Errorf("revision %d of snap %q already installed", revision, name)
+ return fmt.Errorf("revision %s of snap %q already installed", revision, name)
}
}
return nil
}
-const firstLocalRevision = 100001
-
func (m *SnapManager) doPrepareSnap(t *state.Task, _ *tomb.Tomb) error {
st := t.State()
st.Lock()
@@ -158,16 +229,18 @@
return err
}
- if ss.Revision == 0 { // sideloading
- // to not clash with not sideload installs
- // and to not have clashes between them
- // use incremental revisions starting at 100001
- // for sideloads
+ if ss.Revision.Unset() {
+ // Local revisions start at -1 and go down.
+ // (unless it's a really old local revision in which case it needs fixing)
revision := snapst.LocalRevision
- if revision == 0 {
- revision = firstLocalRevision
+ if revision.Unset() || revision.N > 0 {
+ // if revision.N>0 this fixes it
+ revision = snap.R(-1)
} else {
- revision++
+ revision.N--
+ }
+ if !revision.Local() {
+ panic("internal error: invalid local revision built: " + revision.String())
}
snapst.LocalRevision = revision
ss.Revision = revision
@@ -225,7 +298,7 @@
auther = user.Authenticator()
}
- storeInfo, downloadedSnapFile, err := m.backend.Download(ss.Name, ss.Channel, checker, pb, auther)
+ storeInfo, downloadedSnapFile, err := m.backend.Download(ss.Name, ss.Channel, checker, pb, m.store, auther)
if err != nil {
return err
}
@@ -358,6 +431,7 @@
m.runner.Stop()
}
+// TaskSnapSetup returns the SnapSetup with task params hold by or referred to by the the task.
func TaskSnapSetup(t *state.Task) (*SnapSetup, error) {
var ss SnapSetup
@@ -397,7 +471,7 @@
func (m *SnapManager) undoMountSnap(t *state.Task, _ *tomb.Tomb) error {
t.State().Lock()
- ss, err := TaskSnapSetup(t)
+ ss, _, err := snapSetupAndState(t)
t.State().Unlock()
if err != nil {
return err
@@ -424,13 +498,15 @@
}
- if err := m.backend.CheckSnap(ss.SnapPath, curInfo, ss.Flags); err != nil {
+ m.backend.Current(curInfo)
+
+ if err := checkSnap(t.State(), ss.SnapPath, curInfo, Flags(ss.Flags)); err != nil {
return err
}
// TODO Use ss.Revision to obtain the right info to mount
// instead of assuming the candidate is the right one.
- return m.backend.SetupSnap(ss.SnapPath, snapst.Candidate, ss.Flags)
+ return m.backend.SetupSnap(ss.SnapPath, snapst.Candidate)
}
func (m *SnapManager) undoUnlinkCurrentSnap(t *state.Task, _ *tomb.Tomb) error {
@@ -507,7 +583,18 @@
return err
}
- return m.backend.UndoCopySnapData(newInfo, ss.Flags)
+ var oldInfo *snap.Info
+ if cur := snapst.Current(); cur != nil {
+ var err error
+ oldInfo, err = readInfo(ss.Name, cur)
+ if err != nil {
+ return err
+ }
+
+ }
+
+ pb := &TaskProgressAdapter{task: t}
+ return m.backend.UndoCopySnapData(newInfo, oldInfo, pb)
}
func (m *SnapManager) doCopySnapData(t *state.Task, _ *tomb.Tomb) error {
@@ -533,7 +620,8 @@
}
- return m.backend.CopySnapData(newInfo, oldInfo, ss.Flags)
+ pb := &TaskProgressAdapter{task: t}
+ return m.backend.CopySnapData(newInfo, oldInfo, pb)
}
func (m *SnapManager) doLinkSnap(t *state.Task, _ *tomb.Tomb) error {
@@ -557,6 +645,8 @@
if ss.Channel != "" {
snapst.Channel = ss.Channel
}
+ oldTryMode := snapst.TryMode()
+ snapst.SetTryMode(ss.TryMode())
newInfo, err := readInfo(ss.Name, cand)
if err != nil {
@@ -564,15 +654,29 @@
}
st.Unlock()
+ // XXX: this block is slightly ugly, find a pattern when we have more examples
err = m.backend.LinkSnap(newInfo)
+ if err != nil {
+ pb := &TaskProgressAdapter{task: t}
+ err := m.backend.UnlinkSnap(newInfo, pb)
+ if err != nil {
+ st.Lock()
+ t.Errorf("cannot cleanup failed attempt at making snap %q available to the system: %v", ss.Name, err)
+ st.Unlock()
+ }
+ }
st.Lock()
if err != nil {
return err
}
+ // save for undoLinkSnap
+ t.Set("old-trymode", oldTryMode)
t.Set("old-channel", oldChannel)
// Do at the end so we only preserve the new state if it worked.
Set(st, ss.Name, snapst)
+ // Make sure if state commits and snapst is mutated we won't be rerun
+ t.SetStatus(state.DoneStatus)
return nil
}
@@ -592,6 +696,11 @@
if err != nil {
return err
}
+ var oldTryMode bool
+ err = t.Get("old-trymode", &oldTryMode)
+ if err != nil {
+ return err
+ }
// relinking of the old snap is done in the undo of unlink-current-snap
@@ -599,6 +708,7 @@
snapst.Sequence = snapst.Sequence[:len(snapst.Sequence)-1]
snapst.Active = false
snapst.Channel = oldChannel
+ snapst.SetTryMode(oldTryMode)
newInfo, err := readInfo(ss.Name, snapst.Candidate)
if err != nil {
@@ -615,5 +725,7 @@
// mark as inactive
Set(st, ss.Name, snapst)
+ // Make sure if state commits and snapst is mutated we won't be rerun
+ t.SetStatus(state.UndoneStatus)
return nil
}
diff -Nru snapd-2.0.5/overlord/snapstate/snapmgr_test.go snapd-2.0.8/overlord/snapstate/snapmgr_test.go
--- snapd-2.0.5/overlord/snapstate/snapmgr_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/snapmgr_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,14 +27,13 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/overlord/auth"
- "github.com/ubuntu-core/snappy/overlord/snapstate"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/snappy"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/overlord/auth"
+ "github.com/snapcore/snapd/overlord/snapstate"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
)
func TestSnapManager(t *testing.T) { TestingT(t) }
@@ -72,11 +71,15 @@
c.Assert(err, IsNil)
s.snapmgr.AddForeignTaskHandlers(s.fakeBackend)
- // XXX: have just one, reset!
snapstate.SetSnapManagerBackend(s.snapmgr, s.fakeBackend)
- snapstate.SetSnapstateBackend(s.fakeBackend)
- s.reset = snapstate.MockReadInfo(s.fakeBackend.ReadInfo)
+ restore1 := snapstate.MockReadInfo(s.fakeBackend.ReadInfo)
+ restore2 := snapstate.MockOpenSnapFile(s.fakeBackend.OpenSnapFile)
+
+ s.reset = func() {
+ restore2()
+ restore1()
+ }
s.state.Lock()
s.user, err = auth.NewUser(s.state, "username", "macaroon", []string{"discharge"})
@@ -88,6 +91,13 @@
s.reset()
}
+func (s *snapmgrTestSuite) TestStore(c *C) {
+ c.Check(s.snapmgr.Store(), NotNil)
+
+ s.snapmgr.ReplaceStore(nil)
+ c.Check(s.snapmgr.Store(), IsNil)
+}
+
func verifyInstallUpdateTasks(c *C, curActive bool, ts *state.TaskSet, st *state.State) {
i := 0
n := 5
@@ -169,7 +179,7 @@
snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
Active: true,
Channel: "edge",
- Sequence: []*snap.SideInfo{{OfficialName: "some-snap", Revision: 11}},
+ Sequence: []*snap.SideInfo{{OfficialName: "some-snap", Revision: snap.R(11)}},
})
ts, err := snapstate.Update(s.state, "some-snap", "some-channel", s.user.ID, 0)
@@ -190,7 +200,7 @@
snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
Active: true,
Channel: "edge",
- Sequence: []*snap.SideInfo{{OfficialName: "some-snap", Revision: 11}},
+ Sequence: []*snap.SideInfo{{OfficialName: "some-snap", Revision: snap.R(11)}},
})
ts, err := snapstate.Update(s.state, "some-snap", "", s.user.ID, 0)
@@ -232,7 +242,7 @@
},
})
- ts, err := snapstate.Remove(s.state, "foo", 0)
+ ts, err := snapstate.Remove(s.state, "foo")
c.Assert(err, IsNil)
i := 0
@@ -259,16 +269,16 @@
Sequence: []*snap.SideInfo{{OfficialName: "some-snap"}},
})
- ts, err := snapstate.Remove(s.state, "some-snap", 0)
+ ts, err := snapstate.Remove(s.state, "some-snap")
c.Assert(err, IsNil)
// need a change to make the tasks visible
s.state.NewChange("remove", "...").AddAll(ts)
- _, err = snapstate.Remove(s.state, "some-snap", 0)
+ _, err = snapstate.Remove(s.state, "some-snap")
c.Assert(err, ErrorMatches, `snap "some-snap" has changes in progress`)
}
-func (s *snapmgrTestSuite) TestInstallIntegration(c *C) {
+func (s *snapmgrTestSuite) TestInstallRunThrough(c *C) {
s.state.Lock()
defer s.state.Unlock()
@@ -291,14 +301,17 @@
channel: "some-channel",
},
fakeOp{
- op: "check-snap",
+ op: "current",
+ old: "",
+ },
+ fakeOp{
+ op: "open-snap-file",
name: "downloaded-snap-path",
- old: "",
},
fakeOp{
op: "setup-snap",
name: "downloaded-snap-path",
- revno: 11,
+ revno: snap.R(11),
},
fakeOp{
op: "copy-data",
@@ -308,7 +321,7 @@
fakeOp{
op: "setup-profiles:Doing",
name: "some-snap",
- revno: 11,
+ revno: snap.R(11),
},
fakeOp{
op: "candidate",
@@ -316,7 +329,7 @@
OfficialName: "some-snap",
Channel: "some-channel",
SnapID: "snapIDsnapidsnapidsnapidsnapidsn",
- Revision: 11,
+ Revision: snap.R(11),
},
},
fakeOp{
@@ -337,7 +350,7 @@
c.Assert(err, IsNil)
c.Assert(ss, DeepEquals, snapstate.SnapSetup{
Name: "some-snap",
- Revision: 11,
+ Revision: snap.R(11),
Channel: "some-channel",
UserID: s.user.ID,
SnapPath: "downloaded-snap-path",
@@ -356,14 +369,14 @@
OfficialName: "some-snap",
Channel: "some-channel",
SnapID: "snapIDsnapidsnapidsnapidsnapidsn",
- Revision: 11,
+ Revision: snap.R(11),
})
}
-func (s *snapmgrTestSuite) TestUpdateIntegration(c *C) {
+func (s *snapmgrTestSuite) TestUpdateRunThrough(c *C) {
si := snap.SideInfo{
OfficialName: "some-snap",
- Revision: 7,
+ Revision: snap.R(7),
}
s.state.Lock()
@@ -375,7 +388,7 @@
})
chg := s.state.NewChange("install", "install a snap")
- ts, err := snapstate.Update(s.state, "some-snap", "some-channel", s.user.ID, snappy.DoInstallGC)
+ ts, err := snapstate.Update(s.state, "some-snap", "some-channel", s.user.ID, 0)
c.Assert(err, IsNil)
chg.AddAll(ts)
@@ -392,31 +405,31 @@
channel: "some-channel",
},
fakeOp{
- op: "check-snap",
- name: "downloaded-snap-path",
- flags: int(snappy.DoInstallGC),
- old: "/snap/some-snap/7",
+ op: "current",
+ old: "/snap/some-snap/7",
+ },
+ fakeOp{
+ op: "open-snap-file",
+ name: "downloaded-snap-path",
},
fakeOp{
op: "setup-snap",
name: "downloaded-snap-path",
- flags: int(snappy.DoInstallGC),
- revno: 11,
+ revno: snap.R(11),
},
fakeOp{
op: "unlink-snap",
name: "/snap/some-snap/7",
},
fakeOp{
- op: "copy-data",
- name: "/snap/some-snap/11",
- flags: int(snappy.DoInstallGC),
- old: "/snap/some-snap/7",
+ op: "copy-data",
+ name: "/snap/some-snap/11",
+ old: "/snap/some-snap/7",
},
fakeOp{
op: "setup-profiles:Doing",
name: "some-snap",
- revno: 11,
+ revno: snap.R(11),
},
fakeOp{
op: "candidate",
@@ -424,7 +437,7 @@
OfficialName: "some-snap",
SnapID: "snapIDsnapidsnapidsnapidsnapidsn",
Channel: "some-channel",
- Revision: 11,
+ Revision: snap.R(11),
},
},
fakeOp{
@@ -449,10 +462,10 @@
c.Assert(ss, DeepEquals, snapstate.SnapSetup{
Name: "some-snap",
Channel: "some-channel",
- Flags: int(snappy.DoInstallGC),
+ Flags: 0,
UserID: s.user.ID,
- Revision: 11,
+ Revision: snap.R(11),
SnapPath: "downloaded-snap-path",
})
@@ -468,20 +481,20 @@
c.Assert(snapst.Sequence[0], DeepEquals, &snap.SideInfo{
OfficialName: "some-snap",
Channel: "",
- Revision: 7,
+ Revision: snap.R(7),
})
c.Assert(snapst.Sequence[1], DeepEquals, &snap.SideInfo{
OfficialName: "some-snap",
Channel: "some-channel",
SnapID: "snapIDsnapidsnapidsnapidsnapidsn",
- Revision: 11,
+ Revision: snap.R(11),
})
}
-func (s *snapmgrTestSuite) TestUpdateUndoIntegration(c *C) {
+func (s *snapmgrTestSuite) TestUpdateUndoRunThrough(c *C) {
si := snap.SideInfo{
OfficialName: "some-snap",
- Revision: 7,
+ Revision: snap.R(7),
}
s.state.Lock()
@@ -493,7 +506,7 @@
})
chg := s.state.NewChange("install", "install a snap")
- ts, err := snapstate.Update(s.state, "some-snap", "some-channel", s.user.ID, snappy.DoInstallGC)
+ ts, err := snapstate.Update(s.state, "some-snap", "some-channel", s.user.ID, 0)
c.Assert(err, IsNil)
chg.AddAll(ts)
@@ -512,31 +525,31 @@
channel: "some-channel",
},
{
- op: "check-snap",
- name: "downloaded-snap-path",
- flags: int(snappy.DoInstallGC),
- old: "/snap/some-snap/7",
+ op: "current",
+ old: "/snap/some-snap/7",
+ },
+ {
+ op: "open-snap-file",
+ name: "downloaded-snap-path",
},
{
op: "setup-snap",
name: "downloaded-snap-path",
- flags: int(snappy.DoInstallGC),
- revno: 11,
+ revno: snap.R(11),
},
{
op: "unlink-snap",
name: "/snap/some-snap/7",
},
{
- op: "copy-data",
- name: "/snap/some-snap/11",
- flags: int(snappy.DoInstallGC),
- old: "/snap/some-snap/7",
+ op: "copy-data",
+ name: "/snap/some-snap/11",
+ old: "/snap/some-snap/7",
},
{
op: "setup-profiles:Doing",
name: "some-snap",
- revno: 11,
+ revno: snap.R(11),
},
{
op: "candidate",
@@ -544,22 +557,26 @@
OfficialName: "some-snap",
SnapID: "snapIDsnapidsnapidsnapidsnapidsn",
Channel: "some-channel",
- Revision: 11,
+ Revision: snap.R(11),
},
},
{
op: "link-snap.failed",
name: "/snap/some-snap/11",
},
- // no unlink-snap here is expected!
+ {
+ op: "unlink-snap",
+ name: "/snap/some-snap/11",
+ },
{
op: "setup-profiles:Undoing",
name: "some-snap",
- revno: 11,
+ revno: snap.R(11),
},
{
op: "undo-copy-snap-data",
name: "/snap/some-snap/11",
+ old: "/snap/some-snap/7",
},
{
op: "link-snap",
@@ -585,14 +602,14 @@
c.Assert(snapst.Sequence[0], DeepEquals, &snap.SideInfo{
OfficialName: "some-snap",
Channel: "",
- Revision: 7,
+ Revision: snap.R(7),
})
}
-func (s *snapmgrTestSuite) TestUpdateTotalUndoIntegration(c *C) {
+func (s *snapmgrTestSuite) TestUpdateTotalUndoRunThrough(c *C) {
si := snap.SideInfo{
OfficialName: "some-snap",
- Revision: 7,
+ Revision: snap.R(7),
}
s.state.Lock()
@@ -605,7 +622,7 @@
})
chg := s.state.NewChange("install", "install a snap")
- ts, err := snapstate.Update(s.state, "some-snap", "some-channel", s.user.ID, snappy.DoInstallGC)
+ ts, err := snapstate.Update(s.state, "some-snap", "some-channel", s.user.ID, 0)
c.Assert(err, IsNil)
chg.AddAll(ts)
@@ -629,31 +646,31 @@
channel: "some-channel",
},
{
- op: "check-snap",
- name: "downloaded-snap-path",
- flags: int(snappy.DoInstallGC),
- old: "/snap/some-snap/7",
+ op: "current",
+ old: "/snap/some-snap/7",
+ },
+ {
+ op: "open-snap-file",
+ name: "downloaded-snap-path",
},
{
op: "setup-snap",
name: "downloaded-snap-path",
- flags: int(snappy.DoInstallGC),
- revno: 11,
+ revno: snap.R(11),
},
{
op: "unlink-snap",
name: "/snap/some-snap/7",
},
{
- op: "copy-data",
- name: "/snap/some-snap/11",
- flags: int(snappy.DoInstallGC),
- old: "/snap/some-snap/7",
+ op: "copy-data",
+ name: "/snap/some-snap/11",
+ old: "/snap/some-snap/7",
},
{
op: "setup-profiles:Doing",
name: "some-snap",
- revno: 11,
+ revno: snap.R(11),
},
{
op: "candidate",
@@ -661,7 +678,7 @@
OfficialName: "some-snap",
SnapID: "snapIDsnapidsnapidsnapidsnapidsn",
Channel: "some-channel",
- Revision: 11,
+ Revision: snap.R(11),
},
},
{
@@ -676,11 +693,12 @@
{
op: "setup-profiles:Undoing",
name: "some-snap",
- revno: 11,
+ revno: snap.R(11),
},
{
op: "undo-copy-snap-data",
name: "/snap/some-snap/11",
+ old: "/snap/some-snap/7",
},
{
op: "link-snap",
@@ -707,14 +725,14 @@
c.Assert(snapst.Sequence[0], DeepEquals, &snap.SideInfo{
OfficialName: "some-snap",
Channel: "",
- Revision: 7,
+ Revision: snap.R(7),
})
}
-func (s *snapmgrTestSuite) TestUpdateSameRevisionIntegration(c *C) {
+func (s *snapmgrTestSuite) TestUpdateSameRevisionRunThrough(c *C) {
si := snap.SideInfo{
OfficialName: "some-snap",
- Revision: 7,
+ Revision: snap.R(7),
}
s.state.Lock()
@@ -726,7 +744,7 @@
})
chg := s.state.NewChange("install", "install a snap")
- ts, err := snapstate.Update(s.state, "some-snap", "channel-for-7", s.user.ID, snappy.DoInstallGC)
+ ts, err := snapstate.Update(s.state, "some-snap", "channel-for-7", s.user.ID, 0)
c.Assert(err, IsNil)
chg.AddAll(ts)
@@ -761,7 +779,7 @@
c.Assert(snapst.Sequence[0], DeepEquals, &snap.SideInfo{
OfficialName: "some-snap",
Channel: "",
- Revision: 7,
+ Revision: snap.R(7),
})
}
@@ -781,7 +799,10 @@
}
-func (s *snapmgrTestSuite) TestInstallFirstLocalIntegration(c *C) {
+func (s *snapmgrTestSuite) TestInstallFirstLocalRunThrough(c *C) {
+ // use the real thing for this one
+ snapstate.MockOpenSnapFile(snapstate.OpenSnapFileImpl)
+
s.state.Lock()
defer s.state.Unlock()
@@ -797,15 +818,19 @@
s.settle()
s.state.Lock()
- // ensure only local install was run, i.e. first action is check-snap
+ // ensure only local install was run, i.e. first actions are pseudo-action current
c.Assert(s.fakeBackend.ops, HasLen, 6)
- c.Check(s.fakeBackend.ops[0].op, Equals, "check-snap")
- c.Check(s.fakeBackend.ops[0].name, Matches, `.*/mock_1.0_all.snap`)
+ c.Check(s.fakeBackend.ops[0].op, Equals, "current")
+ c.Check(s.fakeBackend.ops[0].old, Equals, "")
+ // and setup-snap
+ c.Check(s.fakeBackend.ops[1].op, Equals, "setup-snap")
+ c.Check(s.fakeBackend.ops[1].name, Matches, `.*/mock_1.0_all.snap`)
+ c.Check(s.fakeBackend.ops[1].revno, Equals, snap.R("x1"))
c.Check(s.fakeBackend.ops[4].op, Equals, "candidate")
- c.Check(s.fakeBackend.ops[4].sinfo, DeepEquals, snap.SideInfo{Revision: 100001})
+ c.Check(s.fakeBackend.ops[4].sinfo, DeepEquals, snap.SideInfo{Revision: snap.R(-1)})
c.Check(s.fakeBackend.ops[5].op, Equals, "link-snap")
- c.Check(s.fakeBackend.ops[5].name, Equals, "/snap/mock/100001")
+ c.Check(s.fakeBackend.ops[5].name, Equals, "/snap/mock/x1")
// verify snapSetup info
var ss snapstate.SnapSetup
@@ -814,7 +839,7 @@
c.Assert(err, IsNil)
c.Assert(ss, DeepEquals, snapstate.SnapSetup{
Name: "mock",
- Revision: 100001,
+ Revision: snap.R(-1),
SnapPath: mockSnap,
})
@@ -828,19 +853,22 @@
c.Assert(snapst.Sequence[0], DeepEquals, &snap.SideInfo{
OfficialName: "",
Channel: "",
- Revision: 100001,
+ Revision: snap.R(-1),
})
- c.Assert(snapst.LocalRevision, Equals, 100001)
+ c.Assert(snapst.LocalRevision, Equals, snap.R(-1))
}
-func (s *snapmgrTestSuite) TestInstallSubequentLocalIntegration(c *C) {
+func (s *snapmgrTestSuite) TestInstallSubsequentLocalRunThrough(c *C) {
+ // use the real thing for this one
+ snapstate.MockOpenSnapFile(snapstate.OpenSnapFileImpl)
+
s.state.Lock()
defer s.state.Unlock()
snapstate.Set(s.state, "mock", &snapstate.SnapState{
Active: true,
- Sequence: []*snap.SideInfo{{Revision: 100002}},
- LocalRevision: 100002,
+ Sequence: []*snap.SideInfo{{Revision: snap.R(-2)}},
+ LocalRevision: snap.R(-2),
})
mockSnap := makeTestSnap(c, `name: mock
@@ -855,26 +883,30 @@
s.settle()
s.state.Lock()
- // ensure only local install was run, i.e. first action is check-snap
+ // ensure only local install was run, i.e. first action is pseudo-action current
c.Assert(s.fakeBackend.ops, HasLen, 7)
- c.Check(s.fakeBackend.ops[0].op, Equals, "check-snap")
- c.Check(s.fakeBackend.ops[0].name, Matches, `.*/mock_1.0_all.snap`)
+ c.Check(s.fakeBackend.ops[0].op, Equals, "current")
+ c.Check(s.fakeBackend.ops[0].old, Equals, "/snap/mock/x2")
+ // and setup-snap
+ c.Check(s.fakeBackend.ops[1].op, Equals, "setup-snap")
+ c.Check(s.fakeBackend.ops[1].name, Matches, `.*/mock_1.0_all.snap`)
+ c.Check(s.fakeBackend.ops[1].revno, Equals, snap.R("x3"))
c.Check(s.fakeBackend.ops[2].op, Equals, "unlink-snap")
- c.Check(s.fakeBackend.ops[2].name, Equals, "/snap/mock/100002")
+ c.Check(s.fakeBackend.ops[2].name, Equals, "/snap/mock/x2")
c.Check(s.fakeBackend.ops[3].op, Equals, "copy-data")
- c.Check(s.fakeBackend.ops[3].name, Equals, "/snap/mock/100003")
- c.Check(s.fakeBackend.ops[3].old, Equals, "/snap/mock/100002")
+ c.Check(s.fakeBackend.ops[3].name, Equals, "/snap/mock/x3")
+ c.Check(s.fakeBackend.ops[3].old, Equals, "/snap/mock/x2")
c.Check(s.fakeBackend.ops[4].op, Equals, "setup-profiles:Doing")
c.Check(s.fakeBackend.ops[4].name, Equals, "mock")
- c.Check(s.fakeBackend.ops[4].revno, Equals, 100003)
+ c.Check(s.fakeBackend.ops[4].revno, Equals, snap.R(-3))
c.Check(s.fakeBackend.ops[5].op, Equals, "candidate")
- c.Check(s.fakeBackend.ops[5].sinfo, DeepEquals, snap.SideInfo{Revision: 100003})
+ c.Check(s.fakeBackend.ops[5].sinfo, DeepEquals, snap.SideInfo{Revision: snap.R(-3)})
c.Check(s.fakeBackend.ops[6].op, Equals, "link-snap")
- c.Check(s.fakeBackend.ops[6].name, Equals, "/snap/mock/100003")
+ c.Check(s.fakeBackend.ops[6].name, Equals, "/snap/mock/x3")
// verify snapSetup info
var ss snapstate.SnapSetup
@@ -883,7 +915,7 @@
c.Assert(err, IsNil)
c.Assert(ss, DeepEquals, snapstate.SnapSetup{
Name: "mock",
- Revision: 100003,
+ Revision: snap.R(-3),
SnapPath: mockSnap,
})
@@ -898,15 +930,65 @@
c.Assert(snapst.Current(), DeepEquals, &snap.SideInfo{
OfficialName: "",
Channel: "",
- Revision: 100003,
+ Revision: snap.R(-3),
})
- c.Assert(snapst.LocalRevision, Equals, 100003)
+ c.Assert(snapst.LocalRevision, Equals, snap.R(-3))
}
-func (s *snapmgrTestSuite) TestRemoveIntegration(c *C) {
+func (s *snapmgrTestSuite) TestInstallOldSubsequentLocalRunThrough(c *C) {
+ // use the real thing for this one
+ snapstate.MockOpenSnapFile(snapstate.OpenSnapFileImpl)
+
+ s.state.Lock()
+ defer s.state.Unlock()
+
+ snapstate.Set(s.state, "mock", &snapstate.SnapState{
+ Active: true,
+ Sequence: []*snap.SideInfo{{Revision: snap.R(100001)}},
+ LocalRevision: snap.R(100001),
+ })
+
+ mockSnap := makeTestSnap(c, `name: mock
+version: 1.0`)
+ chg := s.state.NewChange("install", "install a local snap")
+ ts, err := snapstate.InstallPath(s.state, "mock", mockSnap, "", 0)
+ c.Assert(err, IsNil)
+ chg.AddAll(ts)
+
+ s.state.Unlock()
+ defer s.snapmgr.Stop()
+ s.settle()
+ s.state.Lock()
+
+ // ensure only local install was run, i.e. first action is pseudo-action current
+ ops := s.fakeBackend.ops
+ c.Assert(ops, HasLen, 7)
+ c.Check(ops[0].op, Equals, "current")
+ c.Check(ops[0].old, Equals, "/snap/mock/100001")
+ // and setup-snap
+ c.Check(ops[1].op, Equals, "setup-snap")
+ c.Check(ops[1].name, Matches, `.*/mock_1.0_all.snap`)
+ c.Check(ops[1].revno, Equals, snap.R("x1"))
+
+ var snapst snapstate.SnapState
+ err = snapstate.Get(s.state, "mock", &snapst)
+ c.Assert(err, IsNil)
+
+ c.Assert(snapst.Active, Equals, true)
+ c.Assert(snapst.Candidate, IsNil)
+ c.Assert(snapst.Sequence, HasLen, 2)
+ c.Assert(snapst.Current(), DeepEquals, &snap.SideInfo{
+ OfficialName: "",
+ Channel: "",
+ Revision: snap.R(-1),
+ })
+ c.Assert(snapst.LocalRevision, Equals, snap.R(-1))
+}
+
+func (s *snapmgrTestSuite) TestRemoveRunThrough(c *C) {
si := snap.SideInfo{
OfficialName: "some-snap",
- Revision: 7,
+ Revision: snap.R(7),
}
s.state.Lock()
@@ -918,7 +1000,7 @@
})
chg := s.state.NewChange("remove", "remove a snap")
- ts, err := snapstate.Remove(s.state, "some-snap", 0)
+ ts, err := snapstate.Remove(s.state, "some-snap")
c.Assert(err, IsNil)
chg.AddAll(ts)
@@ -927,21 +1009,16 @@
s.settle()
s.state.Lock()
- c.Assert(s.fakeBackend.ops, HasLen, 7)
+ c.Assert(s.fakeBackend.ops, HasLen, 6)
expected := []fakeOp{
fakeOp{
- op: "can-remove",
- name: "/snap/some-snap/7",
- active: true,
- },
- fakeOp{
op: "unlink-snap",
name: "/snap/some-snap/7",
},
fakeOp{
op: "remove-profiles:Doing",
name: "some-snap",
- revno: 7,
+ revno: snap.R(7),
},
fakeOp{
op: "remove-snap-data",
@@ -976,7 +1053,7 @@
} else {
expSnapSetup = &snapstate.SnapSetup{
Name: "some-snap",
- Revision: 7,
+ Revision: snap.R(7),
}
}
c.Check(ss, DeepEquals, expSnapSetup, Commentf(t.Kind()))
@@ -988,20 +1065,20 @@
c.Assert(err, Equals, state.ErrNoState)
}
-func (s *snapmgrTestSuite) TestRemoveWithManyRevisionsIntegration(c *C) {
+func (s *snapmgrTestSuite) TestRemoveWithManyRevisionsRunThrough(c *C) {
si3 := snap.SideInfo{
OfficialName: "some-snap",
- Revision: 3,
+ Revision: snap.R(3),
}
si5 := snap.SideInfo{
OfficialName: "some-snap",
- Revision: 5,
+ Revision: snap.R(5),
}
si7 := snap.SideInfo{
OfficialName: "some-snap",
- Revision: 7,
+ Revision: snap.R(7),
}
s.state.Lock()
@@ -1013,7 +1090,7 @@
})
chg := s.state.NewChange("remove", "remove a snap")
- ts, err := snapstate.Remove(s.state, "some-snap", 0)
+ ts, err := snapstate.Remove(s.state, "some-snap")
c.Assert(err, IsNil)
chg.AddAll(ts)
@@ -1022,21 +1099,16 @@
s.settle()
s.state.Lock()
- c.Assert(s.fakeBackend.ops, HasLen, 11)
+ c.Assert(s.fakeBackend.ops, HasLen, 10)
expected := []fakeOp{
{
- op: "can-remove",
- name: "/snap/some-snap/7",
- active: true,
- },
- {
op: "unlink-snap",
name: "/snap/some-snap/7",
},
{
op: "remove-profiles:Doing",
name: "some-snap",
- revno: 7,
+ revno: snap.R(7),
},
{
op: "remove-snap-data",
@@ -1075,7 +1147,7 @@
// verify snapSetup info
tasks := ts.Tasks()
- revnos := []int{7, 3, 5}
+ revnos := []snap.Revision{{7}, {3}, {5}}
whichRevno := 0
for _, t := range tasks {
ss, err := snapstate.TaskSnapSetup(t)
@@ -1106,6 +1178,25 @@
c.Assert(err, Equals, state.ErrNoState)
}
+func (s *snapmgrTestSuite) TestRemoveRefused(c *C) {
+ si := snap.SideInfo{
+ OfficialName: "gadget",
+ Revision: snap.R(7),
+ }
+
+ s.state.Lock()
+ defer s.state.Unlock()
+
+ snapstate.Set(s.state, "gadget", &snapstate.SnapState{
+ Active: true,
+ Sequence: []*snap.SideInfo{&si},
+ })
+
+ _, err := snapstate.Remove(s.state, "gadget")
+
+ c.Check(err, ErrorMatches, `snap "gadget" is not removable`)
+}
+
type snapmgrQuerySuite struct {
st *state.State
}
@@ -1122,8 +1213,8 @@
dirs.SetRootDir(c.MkDir())
// Write a snap.yaml with fake name
- sideInfo11 := &snap.SideInfo{OfficialName: "name1", Revision: 11, EditedSummary: "s11"}
- sideInfo12 := &snap.SideInfo{OfficialName: "name1", Revision: 12, EditedSummary: "s12"}
+ sideInfo11 := &snap.SideInfo{OfficialName: "name1", Revision: snap.R(11), EditedSummary: "s11"}
+ sideInfo12 := &snap.SideInfo{OfficialName: "name1", Revision: snap.R(12), EditedSummary: "s12"}
snaptest.MockSnap(c, `
name: name0
version: 1.1
@@ -1149,11 +1240,11 @@
st.Lock()
defer st.Unlock()
- info, err := snapstate.Info(st, "name1", 11)
+ info, err := snapstate.Info(st, "name1", snap.R(11))
c.Assert(err, IsNil)
c.Check(info.Name(), Equals, "name1")
- c.Check(info.Revision, Equals, 11)
+ c.Check(info.Revision, Equals, snap.R(11))
c.Check(info.Summary(), Equals, "s11")
c.Check(info.Version, Equals, "1.1")
c.Check(info.Description(), Equals, "Lots of text")
@@ -1168,7 +1259,7 @@
c.Assert(err, IsNil)
c.Check(info.Name(), Equals, "name1")
- c.Check(info.Revision, Equals, 12)
+ c.Check(info.Revision, Equals, snap.R(12))
}
func (s *snapmgrQuerySuite) TestActiveInfos(c *C) {
@@ -1182,7 +1273,7 @@
c.Check(infos, HasLen, 1)
c.Check(infos[0].Name(), Equals, "name1")
- c.Check(infos[0].Revision, Equals, 12)
+ c.Check(infos[0].Revision, Equals, snap.R(12))
c.Check(infos[0].Summary(), Equals, "s12")
c.Check(infos[0].Version, Equals, "1.2")
c.Check(infos[0].Description(), Equals, "Lots of text")
@@ -1196,7 +1287,7 @@
_, err := snapstate.GadgetInfo(st)
c.Assert(err, Equals, state.ErrNoState)
- sideInfoGadget := &snap.SideInfo{Revision: 2}
+ sideInfoGadget := &snap.SideInfo{Revision: snap.R(2)}
snaptest.MockSnap(c, `
name: gadget
type: gadget
@@ -1211,7 +1302,7 @@
c.Assert(err, IsNil)
c.Check(info.Name(), Equals, "gadget")
- c.Check(info.Revision, Equals, 2)
+ c.Check(info.Revision, Equals, snap.R(2))
c.Check(info.Version, Equals, "gadget")
c.Check(info.Type, Equals, snap.TypeGadget)
}
@@ -1240,7 +1331,7 @@
c.Assert(err, IsNil)
c.Check(info12.Name(), Equals, "name1")
- c.Check(info12.Revision, Equals, 12)
+ c.Check(info12.Revision, Equals, snap.R(12))
c.Check(info12.Summary(), Equals, "s12")
c.Check(info12.Version, Equals, "1.2")
c.Check(info12.Description(), Equals, "Lots of text")
@@ -1249,7 +1340,7 @@
c.Assert(err, IsNil)
c.Check(info11.Name(), Equals, "name1")
- c.Check(info11.Revision, Equals, 11)
+ c.Check(info11.Revision, Equals, snap.R(11))
c.Check(info11.Version, Equals, "1.1")
}
@@ -1275,6 +1366,70 @@
c.Check(snapStates, HasLen, 0)
}
+func (s *snapmgrTestSuite) TestTrySetsTryMode(c *C) {
+ s.state.Lock()
+ defer s.state.Unlock()
+
+ // make mock try dir
+ tryYaml := filepath.Join(c.MkDir(), "meta", "snap.yaml")
+ err := os.MkdirAll(filepath.Dir(tryYaml), 0755)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(tryYaml, []byte("name: foo\nversion: 1.0"), 0644)
+ c.Assert(err, IsNil)
+
+ chg := s.state.NewChange("try", "try snap")
+ ts, err := snapstate.TryPath(s.state, "foo", filepath.Dir(filepath.Dir(tryYaml)), 0)
+ c.Assert(err, IsNil)
+ chg.AddAll(ts)
+
+ s.state.Unlock()
+ defer s.snapmgr.Stop()
+ s.settle()
+ s.state.Lock()
+
+ // verify snap is in TryMode
+ var snapst snapstate.SnapState
+ err = snapstate.Get(s.state, "foo", &snapst)
+ c.Assert(err, IsNil)
+ c.Check(snapst.TryMode(), Equals, true)
+}
+
+func (s *snapmgrTestSuite) TestTryUndoRemovesTryFlag(c *C) {
+ s.state.Lock()
+ defer s.state.Unlock()
+
+ // simulate existing state for foo
+ var snapst snapstate.SnapState
+ snapst.Sequence = []*snap.SideInfo{
+ {
+ OfficialName: "foo",
+ Revision: snap.R(23),
+ },
+ }
+ snapstate.Set(s.state, "foo", &snapst)
+ c.Check(snapst.TryMode(), Equals, false)
+
+ chg := s.state.NewChange("try", "try snap")
+ ts, err := snapstate.TryPath(s.state, "foo", c.MkDir(), 0)
+ c.Assert(err, IsNil)
+ chg.AddAll(ts)
+
+ last := ts.Tasks()[len(ts.Tasks())-1]
+ terr := s.state.NewTask("error-trigger", "provoking total undo")
+ terr.WaitFor(last)
+ chg.AddTask(terr)
+
+ s.state.Unlock()
+ defer s.snapmgr.Stop()
+ s.settle()
+ s.state.Lock()
+
+ // verify snap is not in try mode, the state got undone
+ err = snapstate.Get(s.state, "foo", &snapst)
+ c.Assert(err, IsNil)
+ c.Check(snapst.TryMode(), Equals, false)
+}
+
type snapStateSuite struct{}
var _ = Suite(&snapStateSuite{})
@@ -1286,6 +1441,32 @@
c.Check(snapst.DevMode(), Equals, true)
}
+func (s *snapStateSuite) TestSnapStateModeSetters(c *C) {
+ snapst := &snapstate.SnapState{}
+ c.Check(snapst.DevMode(), Equals, false)
+ c.Check(snapst.TryMode(), Equals, false)
+
+ snapst.SetTryMode(true)
+ c.Check(snapst.DevMode(), Equals, false)
+ c.Check(snapst.TryMode(), Equals, true)
+
+ snapst.SetDevMode(true)
+ c.Check(snapst.DevMode(), Equals, true)
+ c.Check(snapst.TryMode(), Equals, true)
+
+ snapst.SetTryMode(false)
+ c.Check(snapst.DevMode(), Equals, true)
+ c.Check(snapst.TryMode(), Equals, false)
+
+ snapst.SetDevMode(false)
+ c.Check(snapst.DevMode(), Equals, false)
+ c.Check(snapst.TryMode(), Equals, false)
+
+ snapst.SetDevMode(true)
+ c.Check(snapst.DevMode(), Equals, true)
+ c.Check(snapst.TryMode(), Equals, false)
+}
+
type snapSetupSuite struct{}
var _ = Suite(&snapSetupSuite{})
@@ -1293,6 +1474,47 @@
func (s *snapSetupSuite) TestDevMode(c *C) {
ss := &snapstate.SnapSetup{}
c.Check(ss.DevMode(), Equals, false)
- ss.Flags = int(snappy.DeveloperMode)
+ ss.Flags = snapstate.DevMode
c.Check(ss.DevMode(), Equals, true)
}
+
+type canRemoveSuite struct{}
+
+var _ = Suite(&canRemoveSuite{})
+
+func (s *canRemoveSuite) TestAppAreAlwaysOKToRemove(c *C) {
+ info := &snap.Info{
+ Type: snap.TypeApp,
+ }
+ info.OfficialName = "foo"
+
+ c.Check(snapstate.CanRemove(info, false), Equals, true)
+ c.Check(snapstate.CanRemove(info, true), Equals, true)
+}
+
+func (s *canRemoveSuite) TestActiveGadgetsAreNotOK(c *C) {
+ info := &snap.Info{
+ Type: snap.TypeGadget,
+ }
+ info.OfficialName = "foo"
+
+ c.Check(snapstate.CanRemove(info, false), Equals, true)
+ c.Check(snapstate.CanRemove(info, true), Equals, false)
+}
+
+func (s *canRemoveSuite) TestActiveOSAndKernelAreNotOK(c *C) {
+ os := &snap.Info{
+ Type: snap.TypeOS,
+ }
+ os.OfficialName = "os"
+ kernel := &snap.Info{
+ Type: snap.TypeKernel,
+ }
+ kernel.OfficialName = "krnl"
+
+ c.Check(snapstate.CanRemove(os, false), Equals, true)
+ c.Check(snapstate.CanRemove(os, true), Equals, false)
+
+ c.Check(snapstate.CanRemove(kernel, false), Equals, true)
+ c.Check(snapstate.CanRemove(kernel, true), Equals, false)
+}
diff -Nru snapd-2.0.5/overlord/snapstate/snapstate.go snapd-2.0.8/overlord/snapstate/snapstate.go
--- snapd-2.0.5/overlord/snapstate/snapstate.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/snapstate/snapstate.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,18 +24,40 @@
"encoding/json"
"fmt"
- "github.com/ubuntu-core/snappy/i18n"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snappy"
+ "github.com/snapcore/snapd/i18n"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/snap"
)
-// allow exchange in the tests
-// XXX once we reimplent CanRemove directly here, this goes away
-var be managerBackend = &defaultBackend{}
+// Flags are used to pass additional flags to operations and to keep track of snap modes.
+type Flags int
-func doInstall(s *state.State, curActive bool, snapName, snapPath, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+const (
+ // DevMode switches confinement to non-enforcing mode.
+ DevMode = 1 << iota
+ // TryMode is set for snaps installed to try directly from a local directory.
+ TryMode
+
+ // the following flag values cannot be used until we drop the
+ // backward compatible support for flags values in SnapSetup
+ // that were based on snappy.* flags, after that we can
+ // start using them
+ interimUnusableLegacyFlagValueMin
+ interimUnusableLegacyFlagValue1
+ interimUnusableLegacyFlagValue2
+ interimUnusableLegacyFlagValueLast
+
+ // the following flag value is the first that can be grabbed
+ // for use in the interim time while we have the backward compatible
+ // support
+ firstInterimUsableFlagValue
+ // if we need flags for just SnapSetup it may be easier
+ // to start a new sequence from the other end with:
+ // 0x40000000 >> iota
+)
+
+func doInstall(s *state.State, curActive bool, snapName, snapPath, channel string, userID int, flags Flags) (*state.TaskSet, error) {
if err := checkChangeConflict(s, snapName); err != nil {
return nil, err
}
@@ -48,7 +70,7 @@
ss := SnapSetup{
Channel: channel,
UserID: userID,
- Flags: int(flags),
+ Flags: SnapSetupFlags(flags),
}
ss.Name = snapName
ss.SnapPath = snapPath
@@ -116,7 +138,7 @@
// Install returns a set of tasks for installing snap.
// Note that the state must be locked by the caller.
-func Install(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+func Install(s *state.State, name, channel string, userID int, flags Flags) (*state.TaskSet, error) {
var snapst SnapState
err := Get(s, name, &snapst)
if err != nil && err != state.ErrNoState {
@@ -131,7 +153,7 @@
// InstallPath returns a set of tasks for installing snap from a file path.
// Note that the state must be locked by the caller.
-func InstallPath(s *state.State, name, path, channel string, flags snappy.InstallFlags) (*state.TaskSet, error) {
+func InstallPath(s *state.State, name, path, channel string, flags Flags) (*state.TaskSet, error) {
var snapst SnapState
err := Get(s, name, &snapst)
if err != nil && err != state.ErrNoState {
@@ -141,9 +163,17 @@
return doInstall(s, snapst.Active, name, path, channel, 0, flags)
}
+// TryPath returns a set of tasks for trying a snap from a file path.
+// Note that the state must be locked by the caller.
+func TryPath(s *state.State, name, path string, flags Flags) (*state.TaskSet, error) {
+ flags |= TryMode
+
+ return InstallPath(s, name, path, "", flags)
+}
+
// Update initiates a change updating a snap.
// Note that the state must be locked by the caller.
-func Update(s *state.State, name, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) {
+func Update(s *state.State, name, channel string, userID int, flags Flags) (*state.TaskSet, error) {
var snapst SnapState
err := Get(s, name, &snapst)
if err != nil && err != state.ErrNoState {
@@ -161,11 +191,10 @@
return doInstall(s, snapst.Active, name, "", channel, userID, flags)
}
-func removeInactiveRevision(s *state.State, name string, revision int, flags snappy.RemoveFlags) *state.TaskSet {
+func removeInactiveRevision(s *state.State, name string, revision snap.Revision) *state.TaskSet {
ss := SnapSetup{
Name: name,
Revision: revision,
- Flags: int(flags),
}
clearData := s.NewTask("clear-snap", fmt.Sprintf(i18n.G("Remove data for snap %q"), name))
@@ -178,9 +207,27 @@
return state.NewTaskSet(clearData, discardSnap)
}
+// canRemove verifies that a snap can be removed.
+func canRemove(s *snap.Info, active bool) bool {
+ // Gadget snaps should not be removed as they are a key
+ // building block for Gadgets. Pruning non active ones
+ // is acceptable.
+ if s.Type == snap.TypeGadget && active {
+ return false
+ }
+
+ // You never want to remove an active kernel or OS
+ if (s.Type == snap.TypeKernel || s.Type == snap.TypeOS) && active {
+ return false
+ }
+ // TODO: on classic likely let remove core even if active if it's only snap left.
+
+ return true
+}
+
// Remove returns a set of tasks for removing snap.
// Note that the state must be locked by the caller.
-func Remove(s *state.State, name string, flags snappy.RemoveFlags) (*state.TaskSet, error) {
+func Remove(s *state.State, name string) (*state.TaskSet, error) {
if err := checkChangeConflict(s, name); err != nil {
return nil, err
}
@@ -205,8 +252,7 @@
}
// check if this is something that can be removed
- // XXX: move CanRemove impl directly in snapstate
- if !be.CanRemove(info, active) {
+ if !canRemove(info, active) {
return nil, fmt.Errorf("snap %q is not removable", name)
}
@@ -214,7 +260,6 @@
ss := SnapSetup{
Name: name,
Revision: revision,
- Flags: int(flags),
}
// trigger remove
@@ -245,7 +290,7 @@
seq := snapst.Sequence
for i := len(seq) - 1; i >= 0; i-- {
si := seq[i]
- addNext(removeInactiveRevision(s, name, si.Revision, flags))
+ addNext(removeInactiveRevision(s, name, si.Revision))
}
discardConns := s.NewTask("discard-conns", fmt.Sprintf(i18n.G("Discard interface connections for snap %q"), name))
@@ -267,7 +312,7 @@
// Info returns the information about the snap with given name and revision.
// Works also for a mounted candidate snap in the process of being installed.
-func Info(s *state.State, name string, revision int) (*snap.Info, error) {
+func Info(s *state.State, name string, revision snap.Revision) (*snap.Info, error) {
var snapst SnapState
err := Get(s, name, &snapst)
if err == state.ErrNoState {
@@ -287,7 +332,7 @@
return readInfo(name, snapst.Candidate)
}
- return nil, fmt.Errorf("cannot find snap %q at revision %d", name, revision)
+ return nil, fmt.Errorf("cannot find snap %q at revision %s", name, revision.String())
}
// Current returns the information about the current revision of a snap with the given name.
diff -Nru snapd-2.0.5/overlord/state/change_test.go snapd-2.0.8/overlord/state/change_test.go
--- snapd-2.0.5/overlord/state/change_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/state/change_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/state"
"time"
)
diff -Nru snapd-2.0.5/overlord/state/state.go snapd-2.0.8/overlord/state/state.go
--- snapd-2.0.5/overlord/state/state.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/state/state.go 2016-06-08 05:58:01.000000000 +0000
@@ -30,7 +30,7 @@
"sync/atomic"
"time"
- "github.com/ubuntu-core/snappy/logger"
+ "github.com/snapcore/snapd/logger"
)
// A Backend is used by State to checkpoint on every unlock operation
diff -Nru snapd-2.0.5/overlord/state/state_test.go snapd-2.0.8/overlord/state/state_test.go
--- snapd-2.0.5/overlord/state/state_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/state/state_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/state"
)
func TestState(t *testing.T) { TestingT(t) }
diff -Nru snapd-2.0.5/overlord/state/task.go snapd-2.0.8/overlord/state/task.go
--- snapd-2.0.5/overlord/state/task.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/state/task.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,7 +23,7 @@
"encoding/json"
"fmt"
- "github.com/ubuntu-core/snappy/logger"
+ "github.com/snapcore/snapd/logger"
"time"
)
diff -Nru snapd-2.0.5/overlord/state/taskrunner.go snapd-2.0.8/overlord/state/taskrunner.go
--- snapd-2.0.5/overlord/state/taskrunner.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/state/taskrunner.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,7 +25,7 @@
"gopkg.in/tomb.v2"
- "github.com/ubuntu-core/snappy/logger"
+ "github.com/snapcore/snapd/logger"
)
// HandlerFunc is the type of function for the handlers
@@ -123,12 +123,16 @@
switch t.Status() {
case DoingStatus:
t.SetStatus(DoneStatus)
+ fallthrough
+ case DoneStatus:
next = t.HaltTasks()
case AbortStatus:
t.SetStatus(DoneStatus) // Not actually aborted.
r.tryUndo(t)
case UndoingStatus:
t.SetStatus(UndoneStatus)
+ fallthrough
+ case UndoneStatus:
next = t.WaitTasks()
}
if len(next) > 0 {
diff -Nru snapd-2.0.5/overlord/state/taskrunner_test.go snapd-2.0.8/overlord/state/taskrunner_test.go
--- snapd-2.0.5/overlord/state/taskrunner_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/state/taskrunner_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,7 +28,7 @@
. "gopkg.in/check.v1"
"gopkg.in/tomb.v2"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/state"
)
type taskRunnerSuite struct{}
@@ -117,7 +117,15 @@
}, {
setup: "t31:do-error t21:undo-error",
result: "t11:do t12:do t21:do t31:do t31:do-error t32:do t32:undo t21:undo t21:undo-error t11:undo",
-}}
+}, {
+ setup: "t21:do-set-ready",
+ result: "t11:do t12:do t21:do t31:do t32:do",
+},
+ {
+ setup: "t31:do-error t21:undo-set-ready",
+ result: "t11:do t12:do t21:do t31:do t31:do-error t32:do t32:undo t21:undo t11:undo",
+ },
+}
func (ts *taskRunnerSuite) TestSequenceTests(c *C) {
sb := &stateBackend{}
@@ -148,6 +156,14 @@
ch <- task.Summary() + ":" + label + "-error"
return errors.New("boom")
}
+ if task.Get(label+"-set-ready", &isSet) == nil && isSet {
+ switch task.Status() {
+ case state.DoingStatus:
+ task.SetStatus(state.DoneStatus)
+ case state.UndoingStatus:
+ task.SetStatus(state.UndoneStatus)
+ }
+ }
return nil
}
}
diff -Nru snapd-2.0.5/overlord/state/task_test.go snapd-2.0.8/overlord/state/task_test.go
--- snapd-2.0.5/overlord/state/task_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/state/task_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,8 +25,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/overlord/state"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/overlord/state"
+ "github.com/snapcore/snapd/testutil"
"time"
)
diff -Nru snapd-2.0.5/overlord/stateengine.go snapd-2.0.8/overlord/stateengine.go
--- snapd-2.0.5/overlord/stateengine.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/stateengine.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,9 +23,9 @@
"fmt"
"sync"
- "github.com/ubuntu-core/snappy/logger"
+ "github.com/snapcore/snapd/logger"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord/state"
)
// StateManager is implemented by types responsible for observing
diff -Nru snapd-2.0.5/overlord/stateengine_test.go snapd-2.0.8/overlord/stateengine_test.go
--- snapd-2.0.5/overlord/stateengine_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/overlord/stateengine_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,8 +24,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/overlord"
- "github.com/ubuntu-core/snappy/overlord/state"
+ "github.com/snapcore/snapd/overlord"
+ "github.com/snapcore/snapd/overlord/state"
)
type stateEngineSuite struct{}
diff -Nru snapd-2.0.5/partition/bootloader_test.go snapd-2.0.8/partition/bootloader_test.go
--- snapd-2.0.5/partition/bootloader_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/partition/bootloader_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,7 +25,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
+ "github.com/snapcore/snapd/dirs"
)
// Hook up check.v1 into the "go test" runner
diff -Nru snapd-2.0.5/partition/grub.go snapd-2.0.8/partition/grub.go
--- snapd-2.0.5/partition/grub.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/partition/grub.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,8 +23,8 @@
"fmt"
"path/filepath"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
"github.com/mvo5/goconfigparser"
)
diff -Nru snapd-2.0.5/partition/grub_test.go snapd-2.0.8/partition/grub_test.go
--- snapd-2.0.5/partition/grub_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/partition/grub_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
"io/ioutil"
"os"
- "github.com/ubuntu-core/snappy/dirs"
+ "github.com/snapcore/snapd/dirs"
. "gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/partition/uboot.go snapd-2.0.8/partition/uboot.go
--- snapd-2.0.5/partition/uboot.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/partition/uboot.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,8 +22,8 @@
import (
"path/filepath"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
"github.com/mvo5/uboot-go/uenv"
)
diff -Nru snapd-2.0.5/po/snappy.pot snapd-2.0.8/po/snappy.pot
--- snapd-2.0.5/po/snappy.pot 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/po/snappy.pot 2016-06-08 05:58:01.000000000 +0000
@@ -7,7 +7,7 @@
msgid ""
msgstr "Project-Id-Version: snappy\n"
"Report-Msgid-Bugs-To: snappy-devel@lists.ubuntu.com\n"
- "POT-Creation-Date: 2016-05-18 23:53-0300\n"
+ "POT-Creation-Date: 2016-06-07 10:40+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -102,6 +102,9 @@
msgid "Install a snap to the system"
msgstr ""
+msgid "List a change's tasks"
+msgstr ""
+
msgid "List installed snaps"
msgstr ""
@@ -133,13 +136,13 @@
msgid "Mount snap %q"
msgstr ""
-msgid "Name\tVersion\tPrice\tSummary"
+msgid "Name\tVersion\tDeveloper\tNotes\tSummary"
msgstr ""
-msgid "Name\tVersion\tRev\tDeveloper"
+msgid "Name\tVersion\tRev\tDeveloper\tNotes"
msgstr ""
-msgid "Name\tVersion\tSummary"
+msgid "No snaps are installed yet. Try 'snap install hello-world'."
msgstr ""
msgid "Password: "
@@ -202,6 +205,13 @@
msgid "This command logs the current user out of the store"
msgstr ""
+#, c-format
+msgid "Try %q snap from %q"
+msgstr ""
+
+msgid "Try an unpacked snap in the system"
+msgstr ""
+
msgid "Two-factor code: "
msgstr ""
@@ -228,6 +238,10 @@
msgstr ""
msgid "\n"
+ "The change command displays a summary of tasks associated to an individual change."
+msgstr ""
+
+msgid "\n"
"The changes command displays a summary of the recent system changes performed."
msgstr ""
@@ -335,6 +349,13 @@
msgstr ""
msgid "\n"
+ "The try command installs an unpacked snap into the system for testing purposes.\n"
+ "The unpacked snap content continues to be used even after installation, so\n"
+ "non-metadata changes there go live instantly. Metadata changes such as those\n"
+ "performed in snap.yaml will require reinstallation to go live.\n"
+msgstr ""
+
+msgid "\n"
"\n"
"The home directory is shared between snappy and the classic dimension.\n"
"Run \"exit\" to leave the classic shell.\n"
@@ -346,6 +367,9 @@
msgid "no interfaces found"
msgstr ""
+msgid "unavailable"
+msgstr ""
+
#, c-format
msgid "unsupported shell %v"
msgstr ""
diff -Nru snapd-2.0.5/policy/policy.go snapd-2.0.8/policy/policy.go
--- snapd-2.0.5/policy/policy.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/policy/policy.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
var (
diff -Nru snapd-2.0.5/provisioning/provisioning.go snapd-2.0.8/provisioning/provisioning.go
--- snapd-2.0.5/provisioning/provisioning.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/provisioning/provisioning.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,9 +23,9 @@
"path/filepath"
"time"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/partition"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/partition"
"gopkg.in/yaml.v2"
)
diff -Nru snapd-2.0.5/provisioning/provisioning_test.go snapd-2.0.8/provisioning/provisioning_test.go
--- snapd-2.0.5/provisioning/provisioning_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/provisioning/provisioning_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
"path/filepath"
"testing"
- "github.com/ubuntu-core/snappy/partition"
+ "github.com/snapcore/snapd/partition"
. "gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/README.md snapd-2.0.8/README.md
--- snapd-2.0.5/README.md 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/README.md 2016-06-08 05:58:01.000000000 +0000
@@ -36,7 +36,7 @@
The easiest way to get the source for `snappy` is to use the `go get` command.
- go get -d -v github.com/ubuntu-core/snappy/...
+ go get -d -v github.com/snapcore/snapd/...
This command will checkout the source of `snappy` and inspect it for any unmet
Go package dependencies, downloading those as well. `go get` will also build
@@ -46,7 +46,7 @@
go help get
At this point you will have the git local repository of the `snappy` source at
-`$GOPATH/github.com/ubuntu-core/snappy`. The source for any
+`$GOPATH/github.com/snapcore/snapd`. The source for any
dependent packages will also be available inside `$GOPATH`.
### Dependencies handling
@@ -69,12 +69,12 @@
To build, once the sources are available and `GOPATH` is set, you can just run
- go build -o /tmp/snap github.com/ubuntu-core/snappy/cmd/snap
+ go build -o /tmp/snap github.com/snapcore/snapd/cmd/snap
to get the `snap` binary in /tmp (or without -o to get it in the current
working directory). Alternatively:
- go install github.com/ubuntu-core/snappy/...
+ go install github.com/snapcore/snapd/...
to have it available in `$GOPATH/bin`
@@ -85,7 +85,7 @@
http://www.ubuntu.com/legal/contributors
Snappy can be found on Github, so in order to fork the source and contribute,
-go to https://github.com/ubuntu-core/snappy. Check out [Github's help
+go to https://github.com/snapcore/snapd. Check out [Github's help
pages](https://help.github.com/) to find out how to set up your local branch,
commit changes and create pull requests.
@@ -132,8 +132,8 @@
connect).
-[travis-image]: https://travis-ci.org/ubuntu-core/snappy.svg?branch=master
-[travis-url]: https://travis-ci.org/ubuntu-core/snappy
+[travis-image]: https://travis-ci.org/snapcore/snapd.svg?branch=master
+[travis-url]: https://travis-ci.org/snapcore/snapd
-[coveralls-image]: https://coveralls.io/repos/ubuntu-core/snappy/badge.svg?branch=master&service=github
-[coveralls-url]: https://coveralls.io/github/ubuntu-core/snappy?branch=master
+[coveralls-image]: https://coveralls.io/repos/snapcore/snapd/badge.svg?branch=master&service=github
+[coveralls-url]: https://coveralls.io/github/snapcore/snapd?branch=master
diff -Nru snapd-2.0.5/release/export_test.go snapd-2.0.8/release/export_test.go
--- snapd-2.0.5/release/export_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/release/export_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -19,8 +19,10 @@
package release
-func MockLSBReleasePath(filename string) (restore func()) {
- old := lsbReleasePath
- lsbReleasePath = filename
- return func() { lsbReleasePath = old }
+var ReadOSRelease = readOSRelease
+
+func MockOSReleasePath(filename string) (restore func()) {
+ old := osReleasePath
+ osReleasePath = filename
+ return func() { osReleasePath = old }
}
diff -Nru snapd-2.0.5/release/release.go snapd-2.0.8/release/release.go
--- snapd-2.0.5/release/release.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/release/release.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,54 +24,81 @@
"io/ioutil"
"strings"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
// Series holds the Ubuntu Core series for snapd to use.
var Series = "16"
-// LSB contains the /etc/lsb-release information of the system.
-type LSB struct {
+// OS contains information about the system extracted from /etc/os-release.
+type OS struct {
ID string
+ Name string
Release string
Codename string
}
-var lsbReleasePath = "/etc/lsb-release"
+var osReleasePath = "/etc/os-release"
-// ReadLSB returns the lsb-release information of the current system.
-func ReadLSB() (*LSB, error) {
- lsb := &LSB{}
+// readOSRelease returns the os-release information of the current system.
+func readOSRelease() (*OS, error) {
+ osRelease := &OS{}
- content, err := ioutil.ReadFile(lsbReleasePath)
+ content, err := ioutil.ReadFile(osReleasePath)
if err != nil {
- return nil, fmt.Errorf("cannot read lsb-release: %s", err)
+ return nil, fmt.Errorf("cannot read os-release: %s", err)
}
for _, line := range strings.Split(string(content), "\n") {
- if strings.HasPrefix(line, "DISTRIB_ID=") {
+ if strings.HasPrefix(line, "ID=") {
tmp := strings.SplitN(line, "=", 2)
- lsb.ID = tmp[1]
+ osRelease.ID = strings.Trim(tmp[1], "\"")
}
- if strings.HasPrefix(line, "DISTRIB_RELEASE=") {
+ if strings.HasPrefix(line, "NAME=") {
tmp := strings.SplitN(line, "=", 2)
- lsb.Release = tmp[1]
+ osRelease.Name = strings.Trim(tmp[1], "\"")
}
- if strings.HasPrefix(line, "DISTRIB_CODENAME=") {
+ if strings.HasPrefix(line, "VERSION_ID=") {
tmp := strings.SplitN(line, "=", 2)
- lsb.Codename = tmp[1]
+ osRelease.Release = strings.Trim(tmp[1], "\"")
}
+ if strings.HasPrefix(line, "UBUNTU_CODENAME=") {
+ tmp := strings.SplitN(line, "=", 2)
+ osRelease.Codename = strings.Trim(tmp[1], "\"")
+ }
+ }
+ if osRelease.Codename == "" {
+ osRelease.Codename = "xenial"
}
- return lsb, nil
+ return osRelease, nil
}
// OnClassic states whether the process is running inside a
// classic Ubuntu system or a native Ubuntu Core image.
var OnClassic bool
+// ReleaseInfo contains data loaded from /etc/os-release on startup.
+var ReleaseInfo OS
+
func init() {
- OnClassic = osutil.FileExists("/var/lib/dpkg/status")
+ osRelease, err := readOSRelease()
+ if err != nil {
+ // Values recommended by os-release(5) as defaults
+ osRelease = &OS{
+ Name: "Linux",
+ ID: "linux",
+ }
+ }
+ ReleaseInfo = *osRelease
+ // Assume that we are running on Classic
+ OnClassic = true
+ // On Ubuntu, dpkg is not present in an all-snap image so the presence of
+ // dpkg status file can be used as an indicator for a classic vs all-snap
+ // system.
+ if osRelease.ID == "ubuntu" {
+ OnClassic = osutil.FileExists("/var/lib/dpkg/status")
+ }
}
// MockOnClassic forces the process to appear inside a classic
@@ -81,3 +108,11 @@
OnClassic = onClassic
return func() { OnClassic = old }
}
+
+// MockReleaseInfo fakes a given information to appear in ReleaseInfo,
+// as if it was read /etc/os-release on startup.
+func MockReleaseInfo(osRelease *OS) (restore func()) {
+ old := ReleaseInfo
+ ReleaseInfo = *osRelease
+ return func() { ReleaseInfo = old }
+}
diff -Nru snapd-2.0.5/release/release_test.go snapd-2.0.8/release/release_test.go
--- snapd-2.0.5/release/release_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/release/release_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,7 +26,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/release"
+ "github.com/snapcore/snapd/release"
)
// Hook up check.v1 into the "go test" runner
@@ -41,39 +41,46 @@
c.Check(release.Series, Equals, "16")
}
-func makeMockLSBRelease(c *C) string {
+func mockOSRelease(c *C) string {
// FIXME: use AddCleanup here once available so that we
// can do release.SetLSBReleasePath() here directly
- mockLSBRelease := filepath.Join(c.MkDir(), "mock-lsb-release")
+ mockOSRelease := filepath.Join(c.MkDir(), "mock-os-release")
s := `
-DISTRIB_ID=Ubuntu
-DISTRIB_RELEASE=18.09
-DISTRIB_CODENAME=awsome
-DISTRIB_DESCRIPTION=I'm not real!
+NAME="Ubuntu"
+VERSION="18.09 (Awesome Artichoke)"
+ID=ubuntu
+ID_LIKE=debian
+PRETTY_NAME="I'm not real!"
+VERSION_ID="18.09"
+HOME_URL="http://www.ubuntu.com/"
+SUPPORT_URL="http://help.ubuntu.com/"
+BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
+UBUNTU_CODENAME=awesome
`
- err := ioutil.WriteFile(mockLSBRelease, []byte(s), 0644)
+ err := ioutil.WriteFile(mockOSRelease, []byte(s), 0644)
c.Assert(err, IsNil)
- return mockLSBRelease
+ return mockOSRelease
}
-func (s *ReleaseTestSuite) TestReadLSB(c *C) {
- reset := release.MockLSBReleasePath(makeMockLSBRelease(c))
+func (s *ReleaseTestSuite) TestReadOSRelease(c *C) {
+ reset := release.MockOSReleasePath(mockOSRelease(c))
defer reset()
- lsb, err := release.ReadLSB()
+ os, err := release.ReadOSRelease()
c.Assert(err, IsNil)
- c.Assert(lsb.ID, Equals, "Ubuntu")
- c.Assert(lsb.Release, Equals, "18.09")
- c.Assert(lsb.Codename, Equals, "awsome")
+ c.Assert(os.ID, Equals, "ubuntu")
+ c.Assert(os.Name, Equals, "Ubuntu")
+ c.Assert(os.Release, Equals, "18.09")
+ c.Assert(os.Codename, Equals, "awesome")
}
-func (s *ReleaseTestSuite) TestReadLSBNotFound(c *C) {
- reset := release.MockLSBReleasePath("not-there")
+func (s *ReleaseTestSuite) TestReadOSReleaseNotFound(c *C) {
+ reset := release.MockOSReleasePath("not-there")
defer reset()
- _, err := release.ReadLSB()
- c.Assert(err, ErrorMatches, "cannot read lsb-release:.*")
+ _, err := release.ReadOSRelease()
+ c.Assert(err, ErrorMatches, "cannot read os-release:.*")
}
func (s *ReleaseTestSuite) TestOnClassic(c *C) {
@@ -85,3 +92,11 @@
defer reset()
c.Assert(release.OnClassic, Equals, false)
}
+
+func (s *ReleaseTestSuite) TestReleaseInfo(c *C) {
+ reset := release.MockReleaseInfo(&release.OS{
+ ID: "distro-id",
+ })
+ defer reset()
+ c.Assert(release.ReleaseInfo.ID, Equals, "distro-id")
+}
diff -Nru snapd-2.0.5/run-checks snapd-2.0.8/run-checks
--- snapd-2.0.5/run-checks 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/run-checks 2016-06-08 05:58:01.000000000 +0000
@@ -108,28 +108,12 @@
# cmd/* test sources are tagged so they are not included in
# special integration test builds
echo Checking 'cmd/*/*_test.go' build tagging
- bad=""
- for cmd in cmd/* ; do
- nottagged=$(ls ${cmd}/*_test.go|grep -v integration_coverage_test|grep -v -F "$(grep -l '!integrationcoverage' ${cmd}/*_test.go)" || true)
-
- if [ -n "${nottagged}" ] ; then
- echo these ${cmd} test files miss the '!integrationcoverage' tag: ${nottagged}
- bad=1
- fi
- done
- if [ -n "${bad}" ] ; then
+ nottagged=$(grep -r --include '*_test.go' --exclude integration_coverage_test.go -L '!integrationcoverage' cmd/*/)
+ if [ -n "${nottagged}" ] ; then
+ echo these test files miss the '!integrationcoverage' tag: ${nottagged}
exit 1
fi
- # pot file
- echo Checking translations
- TMPF="$(mktemp)"
- addtrap "rm -f \"$TMPF\""
- ./update-pot "$TMPF"
- if ! diff -u --ignore-matching-lines=.*POT-Creation-Date.* po/snappy.pot $TMPF; then
- echo "You need to run ./update-pot"
- exit 1
- fi
fi
if [ ! -z "$UNIT" ]; then
@@ -139,7 +123,7 @@
echo "mode: set" > .coverage/coverage.out
echo Building
- go build -tags=excludeintegration -v github.com/ubuntu-core/snappy/...
+ go build -tags=excludeintegration -v github.com/snapcore/snapd/...
# tests
echo Running tests from $(pwd)
@@ -151,7 +135,7 @@
echo Building the integration tests
TMP_INTEGRATION="$(mktemp)"
addtrap "rm -f \"$TMP_INTEGRATION\""
- go build -v -o $TMP_INTEGRATION github.com/ubuntu-core/snappy/integration-tests/
+ go build -v -o $TMP_INTEGRATION github.com/snapcore/snapd/integration-tests/
# the rabbit hole
echo Running the tests for the integration testutils
diff -Nru snapd-2.0.5/snap/container.go snapd-2.0.8/snap/container.go
--- snapd-2.0.5/snap/container.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/snap/container.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,82 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2015 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snap
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap/snapdir"
+ "github.com/snapcore/snapd/snap/squashfs"
+)
+
+// Container is the interface to interact with the low-level snap files
+type Container interface {
+ // ReadFile returns the content of a single file from the snap.
+ ReadFile(relative string) (content []byte, err error)
+
+ // Install copies the snap file to targetPath (and possibly unpacks it to mountDir)
+ Install(targetPath, mountDir string) error
+}
+
+// backend implements a specific snap format
+type snapFormat struct {
+ magic []byte
+ open func(fn string) (Container, error)
+}
+
+// formatHandlers is the registry of known formats, squashfs is the only one atm.
+var formatHandlers = []snapFormat{
+ {squashfs.Magic, func(p string) (Container, error) {
+ return squashfs.New(p), nil
+ }},
+}
+
+// Open opens a given snap file with the right backend
+func Open(path string) (Container, error) {
+
+ // see if it's a snapdir first
+ if osutil.FileExists(filepath.Join(path, "meta", "snap.yaml")) {
+ return snapdir.New(path), nil
+ }
+
+ // open the file and check magic
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, fmt.Errorf("cannot open snap: %v", err)
+ }
+ defer f.Close()
+
+ header := make([]byte, 20)
+ if _, err := f.ReadAt(header, 0); err != nil {
+ return nil, fmt.Errorf("cannot read snap: %v", err)
+ }
+
+ for _, h := range formatHandlers {
+ if bytes.HasPrefix(header, h.magic) {
+ return h.open(path)
+ }
+ }
+
+ return nil, fmt.Errorf("cannot open snap: unknown header: %q", header)
+}
diff -Nru snapd-2.0.5/snap/container_test.go snapd-2.0.8/snap/container_test.go
--- snapd-2.0.5/snap/container_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/snap/container_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,48 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snap_test
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snapdir"
+)
+
+type FileSuite struct{}
+
+var _ = Suite(&FileSuite{})
+
+func (s *FileSuite) TestFileOpenForSnapDir(c *C) {
+ sd := c.MkDir()
+ snapYaml := filepath.Join(sd, "meta", "snap.yaml")
+ err := os.MkdirAll(filepath.Dir(snapYaml), 0755)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(snapYaml, []byte(`name: foo`), 0644)
+ c.Assert(err, IsNil)
+
+ f, err := snap.Open(sd)
+ c.Assert(err, IsNil)
+ c.Assert(f, FitsTypeOf, &snapdir.SnapDir{})
+}
diff -Nru snapd-2.0.5/snap/file.go snapd-2.0.8/snap/file.go
--- snapd-2.0.5/snap/file.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/file.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-
-/*
- * Copyright (C) 2014-2015 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package snap
-
-import (
- "bytes"
- "fmt"
- "os"
-
- "github.com/ubuntu-core/snappy/snap/squashfs"
-)
-
-// File is the interface to interact with the low-level snap files
-type File interface {
- // ReadFile returns the content of a single file from the snap.
- ReadFile(relative string) (content []byte, err error)
-
- // Install copies the snap file to targetPath (and possibly unpacks it to mountDir)
- Install(targetPath, mountDir string) error
-}
-
-// backend implements a specific snap format
-type snapFormat struct {
- magic []byte
- open func(fn string) (File, error)
-}
-
-// formatHandlers is the registry of known formats, squashfs is the only one atm.
-var formatHandlers = []snapFormat{
- {squashfs.Magic, func(p string) (File, error) {
- return squashfs.New(p), nil
- }},
-}
-
-// Open opens a given snap file with the right backend
-func Open(path string) (File, error) {
- f, err := os.Open(path)
- if err != nil {
- return nil, fmt.Errorf("cannot open snap: %v", err)
- }
- defer f.Close()
-
- header := make([]byte, 20)
- if _, err := f.ReadAt(header, 0); err != nil {
- return nil, fmt.Errorf("cannot read snap: %v", err)
- }
-
- for _, h := range formatHandlers {
- if bytes.HasPrefix(header, h.magic) {
- return h.open(path)
- }
- }
-
- return nil, fmt.Errorf("cannot open snap: unknown header: %q", header)
-}
diff -Nru snapd-2.0.5/snap/implicit.go snapd-2.0.8/snap/implicit.go
--- snapd-2.0.5/snap/implicit.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/implicit.go 2016-06-08 05:58:01.000000000 +0000
@@ -19,7 +19,7 @@
package snap
-import "github.com/ubuntu-core/snappy/release"
+import "github.com/snapcore/snapd/release"
var implicitSlots = []string{
"firewall-control",
@@ -38,10 +38,13 @@
}
var implicitClassicSlots = []string{
+ "cups-control",
+ "gsettings",
+ "network-manager",
+ "opengl",
+ "pulseaudio",
"unity7",
"x11",
- "opengl",
- "network-manager",
}
// AddImplicitSlots adds implicitly defined slots to a given snap.
diff -Nru snapd-2.0.5/snap/implicit_test.go snapd-2.0.8/snap/implicit_test.go
--- snapd-2.0.5/snap/implicit_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/implicit_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,9 +20,9 @@
package snap_test
import (
- "github.com/ubuntu-core/snappy/interfaces/builtin"
- "github.com/ubuntu-core/snappy/release"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
. "gopkg.in/check.v1"
)
@@ -56,7 +56,7 @@
c.Assert(info.Slots["unity7"].Interface, Equals, "unity7")
c.Assert(info.Slots["unity7"].Name, Equals, "unity7")
c.Assert(info.Slots["unity7"].Snap, Equals, info)
- c.Assert(info.Slots, HasLen, 17)
+ c.Assert(info.Slots, HasLen, 20)
}
func (s *InfoSnapYamlTestSuite) TestImplicitSlotsAreRealInterfaces(c *C) {
diff -Nru snapd-2.0.5/snap/info.go snapd-2.0.8/snap/info.go
--- snapd-2.0.5/snap/info.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/info.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,11 +24,11 @@
"io/ioutil"
"os"
"path/filepath"
- "strconv"
+ "strings"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/systemd"
- "github.com/ubuntu-core/snappy/timeout"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/systemd"
+ "github.com/snapcore/snapd/timeout"
)
// PlaceInfo offers all the information about where a snap and its data are located and exposed in the filesystem.
@@ -56,13 +56,13 @@
}
// MinimalPlaceInfo returns a PlaceInfo with just the location information for a snap of the given name and revision.
-func MinimalPlaceInfo(name string, revision int) PlaceInfo {
+func MinimalPlaceInfo(name string, revision Revision) PlaceInfo {
return &Info{SideInfo: SideInfo{OfficialName: name, Revision: revision}}
}
// MountDir returns the base directory where it gets mounted of the snap with the given name and revision.
-func MountDir(name string, revision int) string {
- return filepath.Join(dirs.SnapSnapsDir, name, strconv.Itoa(revision))
+func MountDir(name string, revision Revision) string {
+ return filepath.Join(dirs.SnapSnapsDir, name, revision.String())
}
// SideInfo holds snap metadata that is crucial for the tracking of
@@ -78,16 +78,16 @@
// from the store but is not required for working offline should not
// end up in SideInfo.
type SideInfo struct {
- OfficialName string `yaml:"name,omitempty" json:"name,omitempty"`
- SnapID string `yaml:"snap-id" json:"snap-id"`
- Revision int `yaml:"revision" json:"revision"`
- Channel string `yaml:"channel,omitempty" json:"channel,omitempty"`
- Developer string `yaml:"developer,omitempty" json:"developer,omitempty"`
- EditedSummary string `yaml:"summary,omitempty" json:"summary,omitempty"`
- EditedDescription string `yaml:"description,omitempty" json:"description,omitempty"`
- Size int64 `yaml:"size,omitempty" json:"size,omitempty"`
- Sha512 string `yaml:"sha512,omitempty" json:"sha512,omitempty"`
- Private bool `yaml:"private,omitempty" json:"private,omitempty"`
+ OfficialName string `yaml:"name,omitempty" json:"name,omitempty"`
+ SnapID string `yaml:"snap-id" json:"snap-id"`
+ Revision Revision `yaml:"revision" json:"revision"`
+ Channel string `yaml:"channel,omitempty" json:"channel,omitempty"`
+ Developer string `yaml:"developer,omitempty" json:"developer,omitempty"`
+ EditedSummary string `yaml:"summary,omitempty" json:"summary,omitempty"`
+ EditedDescription string `yaml:"description,omitempty" json:"description,omitempty"`
+ Size int64 `yaml:"size,omitempty" json:"size,omitempty"`
+ Sha512 string `yaml:"sha512,omitempty" json:"sha512,omitempty"`
+ Private bool `yaml:"private,omitempty" json:"private,omitempty"`
}
// Info provides information about snaps.
@@ -101,9 +101,14 @@
OriginalSummary string
OriginalDescription string
+ Environment map[string]string
+
LicenseAgreement string
LicenseVersion string
+ Epoch string
+ Confinement ConfinementType
Apps map[string]*AppInfo
+ Hooks map[string]*HookInfo
Plugs map[string]*PlugInfo
Slots map[string]*SlotInfo
@@ -143,10 +148,6 @@
return s.OriginalDescription
}
-func (s *Info) strRevno() string {
- return strconv.Itoa(s.Revision)
-}
-
// MountDir returns the base directory of the snap where it gets mounted.
func (s *Info) MountDir() string {
return MountDir(s.Name(), s.Revision)
@@ -154,12 +155,12 @@
// MountFile returns the path where the snap file that is mounted is installed.
func (s *Info) MountFile() string {
- return filepath.Join(dirs.SnapBlobDir, fmt.Sprintf("%s_%d.snap", s.Name(), s.Revision))
+ return filepath.Join(dirs.SnapBlobDir, fmt.Sprintf("%s_%s.snap", s.Name(), s.Revision))
}
// DataDir returns the data directory of the snap.
func (s *Info) DataDir() string {
- return filepath.Join(dirs.SnapDataDir, s.Name(), s.strRevno())
+ return filepath.Join(dirs.SnapDataDir, s.Name(), s.Revision.String())
}
// CommonDataDir returns the data directory common across revisions of the snap.
@@ -169,7 +170,7 @@
// DataHomeDir returns the per user data directory of the snap.
func (s *Info) DataHomeDir() string {
- return filepath.Join(dirs.SnapDataHomeGlob, s.Name(), s.strRevno())
+ return filepath.Join(dirs.SnapDataHomeGlob, s.Name(), s.Revision.String())
}
// CommonDataHomeDir returns the per user data directory common across revisions of the snap.
@@ -189,6 +190,7 @@
Attrs map[string]interface{}
Label string
Apps map[string]*AppInfo
+ Hooks map[string]*HookInfo
}
// SlotInfo provides information about a slot.
@@ -221,11 +223,21 @@
// TODO: this should go away once we have more plumbing and can change
// things vs refactor
- // https://github.com/ubuntu-core/snappy/pull/794#discussion_r58688496
+ // https://github.com/snapcore/snapd/pull/794#discussion_r58688496
BusName string
Plugs map[string]*PlugInfo
Slots map[string]*SlotInfo
+
+ Environment map[string]string
+}
+
+// HookInfo provides information about a hook.
+type HookInfo struct {
+ Snap *Info
+
+ Name string
+ Plugs map[string]*PlugInfo
}
// SecurityTag returns application-specific security tag.
@@ -279,6 +291,28 @@
return filepath.Join(dirs.SnapServicesDir, app.SecurityTag()+".socket")
}
+func copyEnv(in map[string]string) map[string]string {
+ out := make(map[string]string)
+ for k, v := range in {
+ out[k] = v
+ }
+
+ return out
+}
+
+// Env returns the app specific environment overrides
+func (app *AppInfo) Env() []string {
+ env := []string{}
+ appEnv := copyEnv(app.Snap.Environment)
+ for k, v := range app.Environment {
+ appEnv[k] = v
+ }
+ for k, v := range appEnv {
+ env = append(env, fmt.Sprintf("%s=%s\n", k, v))
+ }
+ return env
+}
+
func infoFromSnapYamlWithSideInfo(meta []byte, si *SideInfo) (*Info, error) {
info, err := InfoFromSnapYaml(meta)
if err != nil {
@@ -297,7 +331,7 @@
snapYamlFn := filepath.Join(MountDir(name, si.Revision), "meta", "snap.yaml")
meta, err := ioutil.ReadFile(snapYamlFn)
if os.IsNotExist(err) {
- return nil, fmt.Errorf("cannot find mounted snap %q at revision %d", name, si.Revision)
+ return nil, fmt.Errorf("cannot find mounted snap %q at revision %s", name, si.Revision)
}
if err != nil {
return nil, err
@@ -308,7 +342,7 @@
// ReadInfoFromSnapFile reads the snap information from the given File
// and completes it with the given side-info if this is not nil.
-func ReadInfoFromSnapFile(snapf File, si *SideInfo) (*Info, error) {
+func ReadInfoFromSnapFile(snapf Container, si *SideInfo) (*Info, error) {
meta, err := snapf.ReadFile("meta/snap.yaml")
if err != nil {
return nil, err
@@ -326,3 +360,14 @@
return info, nil
}
+
+// SplitSnapApp will split a string of the form `snap.app` into
+// the `snap` and the `app` part. It also deals with the special
+// case of snapName == appName.
+func SplitSnapApp(snapApp string) (snap, app string) {
+ l := strings.SplitN(snapApp, ".", 2)
+ if len(l) < 2 {
+ return l[0], l[0]
+ }
+ return l[0], l[1]
+}
diff -Nru snapd-2.0.5/snap/info_snap_yaml.go snapd-2.0.8/snap/info_snap_yaml.go
--- snapd-2.0.5/snap/info_snap_yaml.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/info_snap_yaml.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
"gopkg.in/yaml.v2"
- "github.com/ubuntu-core/snappy/systemd"
- "github.com/ubuntu-core/snappy/timeout"
+ "github.com/snapcore/snapd/systemd"
+ "github.com/snapcore/snapd/timeout"
)
type snapYaml struct {
@@ -40,9 +40,13 @@
Summary string `yaml:"summary"`
LicenseAgreement string `yaml:"license-agreement,omitempty"`
LicenseVersion string `yaml:"license-version,omitempty"`
+ Epoch string `yaml:"epoch,omitempty"`
+ Confinement ConfinementType `yaml:"confinement,omitempty"`
+ Environment map[string]string `yaml:"environment,omitempty"`
Plugs map[string]interface{} `yaml:"plugs,omitempty"`
Slots map[string]interface{} `yaml:"slots,omitempty"`
Apps map[string]appYaml `yaml:"apps,omitempty"`
+ Hooks map[string]hookYaml `yaml:"hooks,omitempty"`
}
type plugYaml struct {
@@ -74,11 +78,17 @@
BusName string `yaml:"bus-name,omitempty"`
+ Environment map[string]string `yaml:"environment,omitempty"`
+
Socket bool `yaml:"socket,omitempty"`
ListenStream string `yaml:"listen-stream,omitempty"`
SocketMode string `yaml:"socket-mode,omitempty"`
}
+type hookYaml struct {
+ PlugNames []string `yaml:"plugs,omitempty"`
+}
+
// InfoFromSnapYaml creates a new info based on the given snap.yaml data
func InfoFromSnapYaml(yamlData []byte) (*Info, error) {
var y snapYaml
@@ -86,7 +96,49 @@
if err != nil {
return nil, fmt.Errorf("info failed to parse: %s", err)
}
- // Defaults
+
+ snap := infoSkeletonFromSnapYaml(y)
+ setEnvironmentFromSnapYaml(y, snap)
+
+ // Collect top-level definitions of plugs and slots
+ if err := setPlugsFromSnapYaml(y, snap); err != nil {
+ return nil, err
+ }
+ if err := setSlotsFromSnapYaml(y, snap); err != nil {
+ return nil, err
+ }
+
+ // At this point snap.Plugs and snap.Slots only contain globally-declared
+ // plugs and slots. We're about to change that, but we need to remember the
+ // global ones for later, so save their names.
+ globalPlugNames := make([]string, 0, len(snap.Plugs))
+ for plugName := range snap.Plugs {
+ globalPlugNames = append(globalPlugNames, plugName)
+ }
+
+ globalSlotNames := make([]string, 0, len(snap.Slots))
+ for slotName := range snap.Slots {
+ globalSlotNames = append(globalSlotNames, slotName)
+ }
+
+ // Collect all apps and hooks
+ setAppsFromSnapYaml(y, snap)
+ setHooksFromSnapYaml(y, snap)
+
+ // Bind unbound plugs to all apps and hooks
+ bindUnboundPlugs(globalPlugNames, snap)
+
+ // Bind unbound slots to all apps
+ bindUnboundSlots(globalSlotNames, snap)
+
+ // FIXME: validation of the fields
+ return snap, nil
+}
+
+// infoSkeletonFromSnapYaml initializes an Info without apps, hook, plugs, or
+// slots
+func infoSkeletonFromSnapYaml(y snapYaml) *Info {
+ // Prepare defaults
architectures := []string{"all"}
if len(y.Architectures) != 0 {
architectures = y.Architectures
@@ -95,7 +147,16 @@
if y.Type != "" {
typ = y.Type
}
- // Construct snap skeleton, without apps, plugs and slots
+ epoch := "0"
+ if y.Epoch != "" {
+ epoch = y.Epoch
+ }
+ confinement := StrictConfinement
+ if y.Confinement != "" {
+ confinement = y.Confinement
+ }
+
+ // Construct snap skeleton without apps, hooks, plugs, or slots
snap := &Info{
SuggestedName: y.Name,
Version: y.Version,
@@ -106,16 +167,31 @@
OriginalSummary: y.Summary,
LicenseAgreement: y.LicenseAgreement,
LicenseVersion: y.LicenseVersion,
+ Epoch: epoch,
+ Confinement: confinement,
Apps: make(map[string]*AppInfo),
+ Hooks: make(map[string]*HookInfo),
Plugs: make(map[string]*PlugInfo),
Slots: make(map[string]*SlotInfo),
+ Environment: y.Environment,
}
+
sort.Strings(snap.Assumes)
- // Collect top-level definitions of plugs
+
+ return snap
+}
+
+func setEnvironmentFromSnapYaml(y snapYaml, snap *Info) {
+ for k, v := range y.Environment {
+ snap.Environment[k] = v
+ }
+}
+
+func setPlugsFromSnapYaml(y snapYaml, snap *Info) error {
for name, data := range y.Plugs {
iface, label, attrs, err := convertToSlotOrPlugData("plug", name, data)
if err != nil {
- return nil, err
+ return err
}
snap.Plugs[name] = &PlugInfo{
Snap: snap,
@@ -127,12 +203,19 @@
if len(y.Apps) > 0 {
snap.Plugs[name].Apps = make(map[string]*AppInfo)
}
+ if len(y.Hooks) > 0 {
+ snap.Plugs[name].Hooks = make(map[string]*HookInfo)
+ }
}
- // Collect top-level definitions of slots
+
+ return nil
+}
+
+func setSlotsFromSnapYaml(y snapYaml, snap *Info) error {
for name, data := range y.Slots {
iface, label, attrs, err := convertToSlotOrPlugData("slot", name, data)
if err != nil {
- return nil, err
+ return err
}
snap.Slots[name] = &SlotInfo{
Snap: snap,
@@ -145,6 +228,11 @@
snap.Slots[name].Apps = make(map[string]*AppInfo)
}
}
+
+ return nil
+}
+
+func setAppsFromSnapYaml(y snapYaml, snap *Info) {
for appName, yApp := range y.Apps {
// Collect all apps
app := &AppInfo{
@@ -160,6 +248,7 @@
SocketMode: yApp.SocketMode,
ListenStream: yApp.ListenStream,
BusName: yApp.BusName,
+ Environment: yApp.Environment,
}
if len(y.Plugs) > 0 || len(yApp.PlugNames) > 0 {
app.Plugs = make(map[string]*PlugInfo)
@@ -199,16 +288,72 @@
slot.Apps[appName] = app
}
}
- // Bind plugs/slots that are not app-bound to all apps
- for plugName, plug := range snap.Plugs {
- if len(plug.Apps) == 0 {
+}
+
+func setHooksFromSnapYaml(y snapYaml, snap *Info) {
+ for hookName, yHook := range y.Hooks {
+ // Collect all hooks
+ hook := &HookInfo{
+ Snap: snap,
+ Name: hookName,
+ }
+ if len(y.Plugs) > 0 || len(yHook.PlugNames) > 0 {
+ hook.Plugs = make(map[string]*PlugInfo)
+ }
+ snap.Hooks[hookName] = hook
+ // Bind all plugs/slots listed in this hook
+ for _, plugName := range yHook.PlugNames {
+ plug, ok := snap.Plugs[plugName]
+ if !ok {
+ // Create implicit plug definitions if required
+ plug = &PlugInfo{
+ Snap: snap,
+ Name: plugName,
+ Interface: plugName,
+ Hooks: make(map[string]*HookInfo),
+ }
+ snap.Plugs[plugName] = plug
+ } else if plug.Hooks == nil {
+ plug.Hooks = make(map[string]*HookInfo)
+ }
+ hook.Plugs[plugName] = plug
+ plug.Hooks[hookName] = hook
+ }
+ }
+}
+
+func bindUnboundPlugs(plugNames []string, snap *Info) error {
+ for _, plugName := range plugNames {
+ plug, ok := snap.Plugs[plugName]
+ if !ok {
+ return fmt.Errorf("no plug named %q", plugName)
+ }
+
+ // A plug is considered unbound if it isn't being used by any apps
+ // or hooks. In which case we bind them to all apps and hooks.
+ if len(plug.Apps) == 0 && len(plug.Hooks) == 0 {
for appName, app := range snap.Apps {
app.Plugs[plugName] = plug
plug.Apps[appName] = app
}
+
+ for hookName, hook := range snap.Hooks {
+ hook.Plugs[plugName] = plug
+ plug.Hooks[hookName] = hook
+ }
}
}
- for slotName, slot := range snap.Slots {
+
+ return nil
+}
+
+func bindUnboundSlots(slotNames []string, snap *Info) error {
+ for _, slotName := range slotNames {
+ slot, ok := snap.Slots[slotName]
+ if !ok {
+ return fmt.Errorf("no slot named %q", slotName)
+ }
+
if len(slot.Apps) == 0 {
for appName, app := range snap.Apps {
app.Slots[slotName] = slot
@@ -216,8 +361,8 @@
}
}
}
- // FIXME: validation of the fields
- return snap, nil
+
+ return nil
}
func convertToSlotOrPlugData(plugOrSlot, name string, data interface{}) (iface, label string, attrs map[string]interface{}, err error) {
diff -Nru snapd-2.0.5/snap/info_snap_yaml_test.go snapd-2.0.8/snap/info_snap_yaml_test.go
--- snapd-2.0.5/snap/info_snap_yaml_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/info_snap_yaml_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,9 +25,9 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/systemd"
- "github.com/ubuntu-core/snappy/timeout"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/systemd"
+ "github.com/snapcore/snapd/timeout"
)
// Hook up check.v1 into the "go test" runner
@@ -205,6 +205,44 @@
})
}
+func (s *YamlSuite) TestUnmarshalGlobalPlugBoundToOneApp(c *C) {
+ // NOTE: yaml content cannot use tabs, indent the section with spaces.
+ info, err := snap.InfoFromSnapYaml([]byte(`
+name: snap
+plugs:
+ network-client:
+apps:
+ with-plug:
+ plugs: [network-client]
+ without-plug:
+`))
+ c.Assert(err, IsNil)
+ c.Check(info.Name(), Equals, "snap")
+ c.Check(info.Plugs, HasLen, 1)
+ c.Check(info.Slots, HasLen, 0)
+ c.Check(info.Apps, HasLen, 2)
+
+ plug := info.Plugs["network-client"]
+ withPlugApp := info.Apps["with-plug"]
+ withoutPlugApp := info.Apps["without-plug"]
+ c.Assert(plug, DeepEquals, &snap.PlugInfo{
+ Snap: info,
+ Name: "network-client",
+ Interface: "network-client",
+ Apps: map[string]*snap.AppInfo{withPlugApp.Name: withPlugApp},
+ })
+ c.Assert(withPlugApp, DeepEquals, &snap.AppInfo{
+ Snap: info,
+ Name: "with-plug",
+ Plugs: map[string]*snap.PlugInfo{plug.Name: plug},
+ })
+ c.Assert(withoutPlugApp, DeepEquals, &snap.AppInfo{
+ Snap: info,
+ Name: "without-plug",
+ Plugs: map[string]*snap.PlugInfo{},
+ })
+}
+
func (s *YamlSuite) TestUnmarshalPlugsExplicitlyDefinedExplicitlyBoundToApps(c *C) {
// NOTE: yaml content cannot use tabs, indent the section with spaces.
info, err := snap.InfoFromSnapYaml([]byte(`
@@ -649,6 +687,212 @@
c.Assert(err, ErrorMatches, `slot "serial" uses reserved attribute "\$baud-rate"`)
}
+func (s *YamlSuite) TestUnmarshalHook(c *C) {
+ // NOTE: yaml content cannot use tabs, indent the section with spaces.
+ info, err := snap.InfoFromSnapYaml([]byte(`
+name: snap
+hooks:
+ test-hook:
+`))
+ c.Assert(err, IsNil)
+ c.Check(info.Name(), Equals, "snap")
+ c.Check(info.Plugs, HasLen, 0)
+ c.Check(info.Slots, HasLen, 0)
+ c.Check(info.Apps, HasLen, 0)
+ c.Check(info.Hooks, HasLen, 1)
+
+ hook, ok := info.Hooks["test-hook"]
+ c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'"))
+
+ c.Check(hook, DeepEquals, &snap.HookInfo{
+ Snap: info,
+ Name: "test-hook",
+ Plugs: nil,
+ })
+}
+
+func (s *YamlSuite) TestUnmarshalHookWithPlug(c *C) {
+ // NOTE: yaml content cannot use tabs, indent the section with spaces.
+ info, err := snap.InfoFromSnapYaml([]byte(`
+name: snap
+hooks:
+ test-hook:
+ plugs: [test-plug]
+`))
+ c.Assert(err, IsNil)
+ c.Check(info.Name(), Equals, "snap")
+ c.Check(info.Plugs, HasLen, 1)
+ c.Check(info.Slots, HasLen, 0)
+ c.Check(info.Apps, HasLen, 0)
+ c.Check(info.Hooks, HasLen, 1)
+
+ plug, ok := info.Plugs["test-plug"]
+ c.Assert(ok, Equals, true, Commentf("Expected plugs to include 'test-plug'"))
+ hook, ok := info.Hooks["test-hook"]
+ c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'"))
+
+ c.Check(plug, DeepEquals, &snap.PlugInfo{
+ Snap: info,
+ Name: "test-plug",
+ Interface: "test-plug",
+ Hooks: map[string]*snap.HookInfo{hook.Name: hook},
+ })
+ c.Check(hook, DeepEquals, &snap.HookInfo{
+ Snap: info,
+ Name: "test-hook",
+ Plugs: map[string]*snap.PlugInfo{plug.Name: plug},
+ })
+}
+
+func (s *YamlSuite) TestUnmarshalGlobalPlugsBindToHooks(c *C) {
+ // NOTE: yaml content cannot use tabs, indent the section with spaces.
+ info, err := snap.InfoFromSnapYaml([]byte(`
+name: snap
+plugs:
+ test-plug:
+hooks:
+ test-hook:
+`))
+ c.Assert(err, IsNil)
+ c.Check(info.Name(), Equals, "snap")
+ c.Check(info.Plugs, HasLen, 1)
+ c.Check(info.Slots, HasLen, 0)
+ c.Check(info.Apps, HasLen, 0)
+ c.Check(info.Hooks, HasLen, 1)
+
+ plug, ok := info.Plugs["test-plug"]
+ c.Assert(ok, Equals, true, Commentf("Expected plugs to include 'test-plug'"))
+ hook, ok := info.Hooks["test-hook"]
+ c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'"))
+
+ c.Check(plug, DeepEquals, &snap.PlugInfo{
+ Snap: info,
+ Name: "test-plug",
+ Interface: "test-plug",
+ Hooks: map[string]*snap.HookInfo{hook.Name: hook},
+ })
+ c.Check(hook, DeepEquals, &snap.HookInfo{
+ Snap: info,
+ Name: "test-hook",
+ Plugs: map[string]*snap.PlugInfo{plug.Name: plug},
+ })
+}
+
+func (s *YamlSuite) TestUnmarshalGlobalPlugBoundToOneHook(c *C) {
+ // NOTE: yaml content cannot use tabs, indent the section with spaces.
+ info, err := snap.InfoFromSnapYaml([]byte(`
+name: snap
+plugs:
+ test-plug:
+hooks:
+ with-plug:
+ plugs: [test-plug]
+ without-plug:
+`))
+ c.Assert(err, IsNil)
+ c.Check(info.Name(), Equals, "snap")
+ c.Check(info.Plugs, HasLen, 1)
+ c.Check(info.Slots, HasLen, 0)
+ c.Check(info.Apps, HasLen, 0)
+ c.Check(info.Hooks, HasLen, 2)
+
+ plug := info.Plugs["test-plug"]
+ withPlugHook := info.Hooks["with-plug"]
+ withoutPlugHook := info.Hooks["without-plug"]
+ c.Assert(plug, DeepEquals, &snap.PlugInfo{
+ Snap: info,
+ Name: "test-plug",
+ Interface: "test-plug",
+ Hooks: map[string]*snap.HookInfo{withPlugHook.Name: withPlugHook},
+ })
+ c.Assert(withPlugHook, DeepEquals, &snap.HookInfo{
+ Snap: info,
+ Name: "with-plug",
+ Plugs: map[string]*snap.PlugInfo{plug.Name: plug},
+ })
+ c.Assert(withoutPlugHook, DeepEquals, &snap.HookInfo{
+ Snap: info,
+ Name: "without-plug",
+ Plugs: map[string]*snap.PlugInfo{},
+ })
+}
+
+func (s *YamlSuite) TestUnmarshalExplicitGlobalPlugBoundToHook(c *C) {
+ // NOTE: yaml content cannot use tabs, indent the section with spaces.
+ info, err := snap.InfoFromSnapYaml([]byte(`
+name: snap
+plugs:
+ test-plug: test-interface
+hooks:
+ test-hook:
+ plugs: ["test-plug"]
+`))
+ c.Assert(err, IsNil)
+ c.Check(info.Name(), Equals, "snap")
+ c.Check(info.Plugs, HasLen, 1)
+ c.Check(info.Slots, HasLen, 0)
+ c.Check(info.Apps, HasLen, 0)
+ c.Check(info.Hooks, HasLen, 1)
+
+ plug, ok := info.Plugs["test-plug"]
+ c.Assert(ok, Equals, true, Commentf("Expected plugs to include 'test-plug'"))
+ hook, ok := info.Hooks["test-hook"]
+ c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'"))
+
+ c.Check(plug, DeepEquals, &snap.PlugInfo{
+ Snap: info,
+ Name: "test-plug",
+ Interface: "test-interface",
+ Hooks: map[string]*snap.HookInfo{hook.Name: hook},
+ })
+ c.Check(hook, DeepEquals, &snap.HookInfo{
+ Snap: info,
+ Name: "test-hook",
+ Plugs: map[string]*snap.PlugInfo{plug.Name: plug},
+ })
+}
+
+func (s *YamlSuite) TestUnmarshalGlobalPlugBoundToHookNotApp(c *C) {
+ // NOTE: yaml content cannot use tabs, indent the section with spaces.
+ info, err := snap.InfoFromSnapYaml([]byte(`
+name: snap
+plugs:
+ test-plug:
+hooks:
+ test-hook:
+ plugs: [test-plug]
+apps:
+ test-app:
+`))
+ c.Assert(err, IsNil)
+ c.Check(info.Name(), Equals, "snap")
+ c.Check(info.Plugs, HasLen, 1)
+ c.Check(info.Slots, HasLen, 0)
+ c.Check(info.Apps, HasLen, 1)
+ c.Check(info.Hooks, HasLen, 1)
+
+ plug := info.Plugs["test-plug"]
+ hook := info.Hooks["test-hook"]
+ app := info.Apps["test-app"]
+ c.Assert(plug, DeepEquals, &snap.PlugInfo{
+ Snap: info,
+ Name: "test-plug",
+ Interface: "test-plug",
+ Apps: map[string]*snap.AppInfo{},
+ Hooks: map[string]*snap.HookInfo{hook.Name: hook},
+ })
+ c.Assert(hook, DeepEquals, &snap.HookInfo{
+ Snap: info,
+ Name: "test-hook",
+ Plugs: map[string]*snap.PlugInfo{plug.Name: plug},
+ })
+ c.Assert(app, DeepEquals, &snap.AppInfo{
+ Snap: info,
+ Name: "test-app",
+ Plugs: map[string]*snap.PlugInfo{},
+ })
+}
+
func (s *YamlSuite) TestUnmarshalComplexExample(c *C) {
// NOTE: yaml content cannot use tabs, indent the section with spaces.
info, err := snap.InfoFromSnapYaml([]byte(`
@@ -656,6 +900,8 @@
version: 1.2
summary: foo app
type: app
+epoch: 1*
+confinement: devmode
description: |
Foo provides useful services
apps:
@@ -666,6 +912,9 @@
foo:
command: fooctl
plugs: [foo-socket]
+hooks:
+ test-hook:
+ plugs: [foo-socket]
plugs:
foo-socket:
interface: socket
@@ -684,6 +933,8 @@
c.Check(info.Name(), Equals, "foo")
c.Check(info.Version, Equals, "1.2")
c.Check(info.Type, Equals, snap.TypeApp)
+ c.Check(info.Epoch, Equals, "1*")
+ c.Check(info.Confinement, Equals, snap.DevmodeConfinement)
c.Check(info.Summary(), Equals, "foo app")
c.Check(info.Description(), Equals, "Foo provides useful services\n")
c.Check(info.Apps, HasLen, 2)
@@ -695,6 +946,7 @@
app1 := info.Apps["daemon"]
app2 := info.Apps["foo"]
+ hook := info.Hooks["test-hook"]
plug1 := info.Plugs["network"]
plug2 := info.Plugs["network-bind"]
plug3 := info.Plugs["foo-socket"]
@@ -728,6 +980,15 @@
c.Check(app2.Slots, DeepEquals, map[string]*snap.SlotInfo{
slot2.Name: slot2})
+ // hook1 has two plugs ("foo-socket", "logging"). The plug "logging" is
+ // global while "foo-socket" is hook-bound.
+
+ c.Assert(hook, NotNil)
+ c.Check(hook.Snap, Equals, info)
+ c.Check(hook.Name, Equals, "test-hook")
+ c.Check(hook.Plugs, DeepEquals, map[string]*snap.PlugInfo{
+ plug3.Name: plug3, plug4.Name: plug4})
+
// plug1 ("network") is implicitly defined and app-bound to "daemon"
c.Assert(plug1, Not(IsNil))
@@ -803,6 +1064,24 @@
c.Assert(info.Type, Equals, snap.TypeApp)
}
+func (s *YamlSuite) TestSnapYamlEpochDefault(c *C) {
+ y := []byte(`name: binary
+version: 1.0
+`)
+ info, err := snap.InfoFromSnapYaml(y)
+ c.Assert(err, IsNil)
+ c.Assert(info.Epoch, Equals, "0")
+}
+
+func (s *YamlSuite) TestSnapYamlConfinementDefault(c *C) {
+ y := []byte(`name: binary
+version: 1.0
+`)
+ info, err := snap.InfoFromSnapYaml(y)
+ c.Assert(err, IsNil)
+ c.Assert(info.Confinement, Equals, snap.StrictConfinement)
+}
+
func (s *YamlSuite) TestSnapYamlMultipleArchitecturesParsing(c *C) {
y := []byte(`name: binary
version: 1.0
@@ -921,3 +1200,37 @@
},
})
}
+
+func (s *YamlSuite) TestSnapYamlGlobalEnvironment(c *C) {
+ y := []byte(`
+name: foo
+version: 1.0
+environment:
+ foo: bar
+ baz: boom
+`)
+ info, err := snap.InfoFromSnapYaml(y)
+ c.Assert(err, IsNil)
+ c.Assert(info.Environment, DeepEquals, map[string]string{
+ "foo": "bar",
+ "baz": "boom",
+ })
+}
+
+func (s *YamlSuite) TestSnapYamlPerAppEnvironment(c *C) {
+ y := []byte(`
+name: foo
+version: 1.0
+apps:
+ foo:
+ environment:
+ k1: v1
+ k2: v2
+`)
+ info, err := snap.InfoFromSnapYaml(y)
+ c.Assert(err, IsNil)
+ c.Assert(info.Apps["foo"].Environment, DeepEquals, map[string]string{
+ "k1": "v1",
+ "k2": "v2",
+ })
+}
diff -Nru snapd-2.0.5/snap/info_test.go snapd-2.0.8/snap/info_test.go
--- snapd-2.0.5/snap/info_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/info_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,16 +20,18 @@
package snap_test
import (
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
+ "sort"
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/snap/squashfs"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/snap/squashfs"
)
type infoSuite struct{}
@@ -55,14 +57,14 @@
OfficialName: "newname",
EditedSummary: "fixed summary",
EditedDescription: "fixed desc",
- Revision: 1,
+ Revision: snap.R(1),
SnapID: "snapidsnapidsnapidsnapidsnapidsn",
}
c.Check(info.Name(), Equals, "newname")
c.Check(info.Summary(), Equals, "fixed summary")
c.Check(info.Description(), Equals, "fixed desc")
- c.Check(info.Revision, Equals, 1)
+ c.Check(info.Revision, Equals, snap.R(1))
c.Check(info.SnapID, Equals, "snapidsnapidsnapidsnapidsnapidsn")
}
@@ -94,7 +96,7 @@
command: bar-bin -x
`))
c.Assert(err, IsNil)
- info.Revision = 42
+ info.Revision = snap.R(42)
c.Check(info.Apps["bar"].LauncherCommand(), Equals, "/usr/bin/ubuntu-core-launcher snap.foo.bar snap.foo.bar /snap/foo/42/bar-bin -x")
c.Check(info.Apps["foo"].LauncherCommand(), Equals, "/usr/bin/ubuntu-core-launcher snap.foo.foo snap.foo.foo /snap/foo/42/foo-bin")
@@ -109,7 +111,7 @@
`
func (s *infoSuite) TestReadInfo(c *C) {
- si := &snap.SideInfo{Revision: 42, EditedSummary: "esummary"}
+ si := &snap.SideInfo{Revision: snap.R(42), EditedSummary: "esummary"}
snapInfo1 := snaptest.MockSnap(c, sampleYaml, si)
@@ -117,7 +119,7 @@
c.Assert(err, IsNil)
c.Check(snapInfo2.Name(), Equals, "sample")
- c.Check(snapInfo2.Revision, Equals, 42)
+ c.Check(snapInfo2.Revision, Equals, snap.R(42))
c.Check(snapInfo2.Summary(), Equals, "esummary")
c.Check(snapInfo2.Apps["app"].Command, Equals, "foo")
@@ -146,6 +148,27 @@
func (s *infoSuite) TestReadInfoFromSnapFile(c *C) {
yaml := `name: foo
version: 1.0
+type: app
+epoch: 1*
+confinement: devmode`
+ snapPath := makeTestSnap(c, yaml)
+
+ snapf, err := snap.Open(snapPath)
+ c.Assert(err, IsNil)
+
+ info, err := snap.ReadInfoFromSnapFile(snapf, nil)
+ c.Assert(err, IsNil)
+ c.Check(info.Name(), Equals, "foo")
+ c.Check(info.Version, Equals, "1.0")
+ c.Check(info.Type, Equals, snap.TypeApp)
+ c.Check(info.Revision, Equals, snap.R(0))
+ c.Check(info.Epoch, Equals, "1*")
+ c.Check(info.Confinement, Equals, snap.DevmodeConfinement)
+}
+
+func (s *infoSuite) TestReadInfoFromSnapFileMissingEpoch(c *C) {
+ yaml := `name: foo
+version: 1.0
type: app`
snapPath := makeTestSnap(c, yaml)
@@ -157,7 +180,8 @@
c.Check(info.Name(), Equals, "foo")
c.Check(info.Version, Equals, "1.0")
c.Check(info.Type, Equals, snap.TypeApp)
- c.Check(info.Revision, Equals, 0)
+ c.Check(info.Revision, Equals, snap.R(0))
+ c.Check(info.Epoch, Equals, "0") // Defaults to 0
}
func (s *infoSuite) TestReadInfoFromSnapFileWithSideInfo(c *C) {
@@ -171,13 +195,13 @@
info, err := snap.ReadInfoFromSnapFile(snapf, &snap.SideInfo{
OfficialName: "baz",
- Revision: 42,
+ Revision: snap.R(42),
})
c.Assert(err, IsNil)
c.Check(info.Name(), Equals, "baz")
c.Check(info.Version, Equals, "1.0")
c.Check(info.Type, Equals, snap.TypeApp)
- c.Check(info.Revision, Equals, 42)
+ c.Check(info.Revision, Equals, snap.R(42))
}
func (s *infoSuite) TestReadInfoFromSnapFileValidates(c *C) {
@@ -192,3 +216,116 @@
_, err = snap.ReadInfoFromSnapFile(snapf, nil)
c.Assert(err, ErrorMatches, "invalid snap name.*")
}
+
+func (s *infoSuite) TestReadInfoFromSnapFileCatchesInvalidType(c *C) {
+ yaml := `name: foo
+version: 1.0
+type: foo`
+ snapPath := makeTestSnap(c, yaml)
+
+ snapf, err := snap.Open(snapPath)
+ c.Assert(err, IsNil)
+
+ _, err = snap.ReadInfoFromSnapFile(snapf, nil)
+ c.Assert(err, ErrorMatches, ".*invalid snap type.*")
+}
+
+func (s *infoSuite) TestReadInfoFromSnapFileCatchesInvalidConfinement(c *C) {
+ yaml := `name: foo
+version: 1.0
+confinement: foo`
+ snapPath := makeTestSnap(c, yaml)
+
+ snapf, err := snap.Open(snapPath)
+ c.Assert(err, IsNil)
+
+ _, err = snap.ReadInfoFromSnapFile(snapf, nil)
+ c.Assert(err, ErrorMatches, ".*invalid confinement type.*")
+}
+
+func (s *infoSuite) TestAppEnvSimple(c *C) {
+ yaml := `name: foo
+version: 1.0
+type: app
+environment:
+ global-k: global-v
+apps:
+ foo:
+ environment:
+ app-k: app-v
+`
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ env := info.Apps["foo"].Env()
+ sort.Strings(env)
+ c.Check(env, DeepEquals, []string{
+ "app-k=app-v\n",
+ "global-k=global-v\n",
+ })
+}
+
+func (s *infoSuite) TestAppEnvOverrideGlobal(c *C) {
+ yaml := `name: foo
+version: 1.0
+type: app
+environment:
+ global-k: global-v
+ global-and-local: global-v
+apps:
+ foo:
+ environment:
+ app-k: app-v
+ global-and-local: local-v
+`
+ info, err := snap.InfoFromSnapYaml([]byte(yaml))
+ c.Assert(err, IsNil)
+
+ env := info.Apps["foo"].Env()
+ sort.Strings(env)
+ c.Check(env, DeepEquals, []string{
+ "app-k=app-v\n",
+ "global-and-local=local-v\n",
+ "global-k=global-v\n",
+ })
+}
+
+func (s *infoSuite) TestSplitSnapApp(c *C) {
+ for _, t := range []struct {
+ in string
+ out []string
+ }{
+ // normal cases
+ {"foo.bar", []string{"foo", "bar"}},
+ {"foo.bar.baz", []string{"foo", "bar.baz"}},
+ // special case, snapName == appName
+ {"foo", []string{"foo", "foo"}},
+ } {
+ snap, app := snap.SplitSnapApp(t.in)
+ c.Check([]string{snap, app}, DeepEquals, t.out)
+ }
+}
+
+func ExampleSpltiSnapApp() {
+ fmt.Println(snap.SplitSnapApp("hello-world.env"))
+ // Output: hello-world env
+}
+
+func ExampleSpltiSnapAppShort() {
+ fmt.Println(snap.SplitSnapApp("hello-world"))
+ // Output: hello-world hello-world
+}
+
+func (s *infoSuite) TestReadInfoFromSnapFileCatchesInvalidHook(c *C) {
+ yaml := `name: foo
+version: 1.0
+hooks:
+ abc123:`
+ snapPath := makeTestSnap(c, yaml)
+
+ snapf, err := snap.Open(snapPath)
+ c.Assert(err, IsNil)
+
+ _, err = snap.ReadInfoFromSnapFile(snapf, nil)
+ c.Assert(err, ErrorMatches, ".*invalid hook name.*")
+}
diff -Nru snapd-2.0.5/snap/kernel_test.go snapd-2.0.8/snap/kernel_test.go
--- snapd-2.0.5/snap/kernel_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/kernel_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -25,9 +25,9 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
)
type KernelYamlTestSuite struct {
@@ -47,13 +47,13 @@
}
func (s *KernelYamlTestSuite) TestReadKernelYamlMissing(c *C) {
- info := snaptest.MockSnap(c, mockKernelYaml, &snap.SideInfo{Revision: 42})
+ info := snaptest.MockSnap(c, mockKernelYaml, &snap.SideInfo{Revision: snap.R(42)})
_, err := snap.ReadKernelInfo(info)
c.Assert(err, ErrorMatches, ".*meta/kernel.yaml: no such file or directory")
}
func (s *KernelYamlTestSuite) TestReadKernelYamlValid(c *C) {
- info := snaptest.MockSnap(c, mockKernelYaml, &snap.SideInfo{Revision: 42})
+ info := snaptest.MockSnap(c, mockKernelYaml, &snap.SideInfo{Revision: snap.R(42)})
err := ioutil.WriteFile(filepath.Join(info.MountDir(), "meta", "kernel.yaml"), []byte(`version: 4.2`), 0644)
c.Assert(err, IsNil)
diff -Nru snapd-2.0.5/snap/revision.go snapd-2.0.8/snap/revision.go
--- snapd-2.0.5/snap/revision.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/snap/revision.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,111 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snap
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Keep this in sync between snap and client packages.
+
+type Revision struct {
+ N int
+}
+
+func (r Revision) String() string {
+ if r.N == 0 {
+ return "unset"
+ }
+ if r.N < 0 {
+ return fmt.Sprintf("x%d", -r.N)
+ }
+ return strconv.Itoa(int(r.N))
+}
+
+func (r Revision) Unset() bool {
+ return r.N == 0
+}
+
+func (r Revision) Local() bool {
+ return r.N < 0
+}
+
+func (r Revision) Store() bool {
+ return r.N > 0
+}
+
+func (r Revision) MarshalJSON() ([]byte, error) {
+ return []byte(`"` + r.String() + `"`), nil
+}
+
+func (r *Revision) UnmarshalJSON(data []byte) error {
+ if len(data) > 0 && data[0] == '"' && data[len(data)-1] == '"' {
+ parsed, err := ParseRevision(string(data[1 : len(data)-1]))
+ if err == nil {
+ *r = parsed
+ return nil
+ }
+ } else {
+ n, err := strconv.ParseInt(string(data), 10, 64)
+ if err == nil {
+ r.N = int(n)
+ return nil
+ }
+ }
+ return fmt.Errorf("invalid snap revision: %q", data)
+}
+
+// ParseRevisions returns the representation in r as a revision.
+// See R for a function more suitable for hardcoded revisions.
+func ParseRevision(s string) (Revision, error) {
+ if s == "unset" {
+ return Revision{}, nil
+ }
+ if s != "" && s[0] == 'x' {
+ i, err := strconv.Atoi(s[1:])
+ if err == nil && i > 0 {
+ return Revision{-i}, nil
+ }
+ }
+ i, err := strconv.Atoi(s)
+ if err == nil && i > 0 {
+ return Revision{i}, nil
+ }
+ return Revision{}, fmt.Errorf("invalid snap revision: %#v", s)
+}
+
+// R returns a Revision given an int or a string.
+// Providing an invalid revision type or value causes a runtime panic.
+// See ParseRevision for a polite function that does not panic.
+func R(r interface{}) Revision {
+ switch r := r.(type) {
+ case string:
+ revision, err := ParseRevision(r)
+ if err != nil {
+ panic(err)
+ }
+ return revision
+ case int:
+ return Revision{r}
+ default:
+ panic(fmt.Errorf("cannot use %v (%T) as a snap revision", r, r))
+ }
+}
diff -Nru snapd-2.0.5/snap/revision_test.go snapd-2.0.8/snap/revision_test.go
--- snapd-2.0.5/snap/revision_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/snap/revision_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,171 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snap_test
+
+import (
+ "encoding/json"
+ "strconv"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/snap"
+)
+
+// Keep this in sync between snap and client packages.
+
+type revisionSuite struct{}
+
+var _ = Suite(&revisionSuite{})
+
+func (s revisionSuite) TestString(c *C) {
+ c.Assert(snap.R(0).String(), Equals, "unset")
+ c.Assert(snap.R(10).String(), Equals, "10")
+ c.Assert(snap.R(-9).String(), Equals, "x9")
+}
+
+func (s revisionSuite) TestUnset(c *C) {
+ c.Assert(snap.R(0).Unset(), Equals, true)
+ c.Assert(snap.R(10).Unset(), Equals, false)
+ c.Assert(snap.R(-9).Unset(), Equals, false)
+}
+
+func (s revisionSuite) TestLocal(c *C) {
+ c.Assert(snap.R(0).Local(), Equals, false)
+ c.Assert(snap.R(10).Local(), Equals, false)
+ c.Assert(snap.R(-9).Local(), Equals, true)
+}
+
+func (s revisionSuite) TestStore(c *C) {
+ c.Assert(snap.R(0).Store(), Equals, false)
+ c.Assert(snap.R(10).Store(), Equals, true)
+ c.Assert(snap.R(-9).Store(), Equals, false)
+}
+
+func (s revisionSuite) TestJSON(c *C) {
+ for _, n := range []int{0, 10, -9} {
+ r := snap.R(n)
+ data, err := json.Marshal(snap.R(n))
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, `"`+r.String()+`"`)
+
+ var got snap.Revision
+ err = json.Unmarshal(data, &got)
+ c.Assert(err, IsNil)
+ c.Assert(got, Equals, r)
+
+ got = snap.Revision{}
+ err = json.Unmarshal([]byte(strconv.Itoa(r.N)), &got)
+ c.Assert(err, IsNil)
+ c.Assert(got, Equals, r)
+ }
+}
+
+func (s revisionSuite) ParseRevision(c *C) {
+ type testItem struct {
+ s string
+ n int
+ e string
+ }
+
+ var tests = []testItem{{
+ s: "unset",
+ n: 0,
+ }, {
+ s: "x1",
+ n: -1,
+ }, {
+ s: "1",
+ n: 1,
+ }, {
+ s: "x-1",
+ e: `invalid snap revision: "x-1"`,
+ }, {
+ s: "x0",
+ e: `invalid snap revision: "x0"`,
+ }, {
+ s: "-1",
+ e: `invalid snap revision: "-1"`,
+ }, {
+ s: "0",
+ e: `invalid snap revision: "0"`,
+ }}
+
+ for _, test := range tests {
+ r, err := snap.ParseRevision(test.s)
+ if test.e != "" {
+ c.Assert(err.Error(), Equals, test.e)
+ continue
+ }
+ c.Assert(r, Equals, snap.R(test.n))
+ }
+}
+
+func (s *revisionSuite) TestR(c *C) {
+ type testItem struct {
+ v interface{}
+ n int
+ e string
+ }
+
+ var tests = []testItem{{
+ v: 0,
+ n: 0,
+ }, {
+ v: -1,
+ n: -1,
+ }, {
+ v: 1,
+ n: 1,
+ }, {
+ v: "unset",
+ n: 0,
+ }, {
+ v: "x1",
+ n: -1,
+ }, {
+ v: "1",
+ n: 1,
+ }, {
+ v: "x-1",
+ e: `invalid snap revision: "x-1"`,
+ }, {
+ v: "x0",
+ e: `invalid snap revision: "x0"`,
+ }, {
+ v: "-1",
+ e: `invalid snap revision: "-1"`,
+ }, {
+ v: "0",
+ e: `invalid snap revision: "0"`,
+ }, {
+ v: int64(1),
+ e: `cannot use 1 \(int64\) as a snap revision`,
+ }}
+
+ for _, test := range tests {
+ if test.e != "" {
+ f := func() { snap.R(test.v) }
+ c.Assert(f, PanicMatches, test.e)
+ continue
+ }
+
+ c.Assert(snap.R(test.v), Equals, snap.R(test.n))
+ }
+}
diff -Nru snapd-2.0.5/snap/snapdir/snapdir.go snapd-2.0.8/snap/snapdir/snapdir.go
--- snapd-2.0.5/snap/snapdir/snapdir.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/snap/snapdir/snapdir.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,49 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2015 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snapdir
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+// SnapDir is the snapdir based snap.
+type SnapDir struct {
+ path string
+}
+
+// Path returns the path of the backing container.
+func (s *SnapDir) Path() string {
+ return s.path
+}
+
+// New returns a new snap directory container.
+func New(path string) *SnapDir {
+ return &SnapDir{path: path}
+}
+
+func (s *SnapDir) Install(targetPath, mountDir string) error {
+ return os.Symlink(s.path, targetPath)
+}
+
+func (s *SnapDir) ReadFile(file string) (content []byte, err error) {
+ return ioutil.ReadFile(filepath.Join(s.path, file))
+}
diff -Nru snapd-2.0.5/snap/snapdir/snapdir_test.go snapd-2.0.8/snap/snapdir/snapdir_test.go
--- snapd-2.0.5/snap/snapdir/snapdir_test.go 1970-01-01 00:00:00.000000000 +0000
+++ snapd-2.0.8/snap/snapdir/snapdir_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -0,0 +1,63 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2014-2015 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package snapdir_test
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+
+ "github.com/snapcore/snapd/snap/snapdir"
+
+ . "gopkg.in/check.v1"
+)
+
+// Hook up check.v1 into the "go test" runner
+func Test(t *testing.T) { TestingT(t) }
+
+type SnapdirTestSuite struct {
+}
+
+var _ = Suite(&SnapdirTestSuite{})
+
+func (s *SnapdirTestSuite) TestReadFile(c *C) {
+ d := c.MkDir()
+ needle := []byte(`stuff`)
+ err := ioutil.WriteFile(filepath.Join(d, "foo"), needle, 0644)
+ c.Assert(err, IsNil)
+
+ snap := snapdir.New(d)
+ content, err := snap.ReadFile("foo")
+ c.Assert(err, IsNil)
+ c.Assert(content, DeepEquals, needle)
+}
+
+func (s *SnapdirTestSuite) TestInstall(c *C) {
+ tryBaseDir := c.MkDir()
+ snap := snapdir.New(tryBaseDir)
+
+ varLibSnapd := c.MkDir()
+ targetPath := filepath.Join(varLibSnapd, "foo_1.0.snap")
+ err := snap.Install(targetPath, "unused-mount-dir")
+ c.Assert(err, IsNil)
+ symlinkTarget, err := filepath.EvalSymlinks(targetPath)
+ c.Assert(err, IsNil)
+ c.Assert(symlinkTarget, Equals, tryBaseDir)
+}
diff -Nru snapd-2.0.5/snap/snapenv/snapenv.go snapd-2.0.8/snap/snapenv/snapenv.go
--- snapd-2.0.5/snap/snapenv/snapenv.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/snapenv/snapenv.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
"strings"
"text/template"
- "github.com/ubuntu-core/snappy/logger"
+ "github.com/snapcore/snapd/logger"
)
// MakeMapFromEnvList takes a string list of the form "key=value"
diff -Nru snapd-2.0.5/snap/snaptest/build.go snapd-2.0.8/snap/snaptest/build.go
--- snapd-2.0.5/snap/snaptest/build.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/snaptest/build.go 2016-06-08 05:58:01.000000000 +0000
@@ -31,9 +31,9 @@
"strings"
"syscall"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/squashfs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/squashfs"
)
// from click's click.build.ClickBuilderBase, and there from
diff -Nru snapd-2.0.5/snap/snaptest/build_test.go snapd-2.0.8/snap/snaptest/build_test.go
--- snapd-2.0.5/snap/snaptest/build_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/snaptest/build_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,10 +29,10 @@
"strings"
"syscall"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/testutil"
. "gopkg.in/check.v1"
)
diff -Nru snapd-2.0.5/snap/snaptest/snaptest.go snapd-2.0.8/snap/snaptest/snaptest.go
--- snapd-2.0.5/snap/snaptest/snaptest.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/snaptest/snaptest.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,7 +27,7 @@
"gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
// MockSnap puts a snap.yaml file on disk so to mock an installed snap, based on the provided arguments.
diff -Nru snapd-2.0.5/snap/snaptest/snaptest_test.go snapd-2.0.8/snap/snaptest/snaptest_test.go
--- snapd-2.0.5/snap/snaptest/snaptest_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/snaptest/snaptest_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,9 +26,9 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
)
func TestSnapTest(t *testing.T) { TestingT(t) }
@@ -57,11 +57,11 @@
}
func (s *snapTestSuite) TestMockSnap(c *C) {
- snapInfo := snaptest.MockSnap(c, sampleYaml, &snap.SideInfo{Revision: 42})
+ snapInfo := snaptest.MockSnap(c, sampleYaml, &snap.SideInfo{Revision: snap.R(42)})
// Data from YAML is used
c.Check(snapInfo.Name(), Equals, "sample")
// Data from SideInfo is used
- c.Check(snapInfo.Revision, Equals, 42)
+ c.Check(snapInfo.Revision, Equals, snap.R(42))
// The YAML is placed on disk
cont, err := ioutil.ReadFile(filepath.Join(dirs.SnapSnapsDir, "sample", "42", "meta", "snap.yaml"))
c.Assert(err, IsNil)
diff -Nru snapd-2.0.5/snap/squashfs/squashfs.go snapd-2.0.8/snap/squashfs/squashfs.go
--- snapd-2.0.5/snap/squashfs/squashfs.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/squashfs/squashfs.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,7 +29,7 @@
"path/filepath"
"strings"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
// Magic is the magic prefix of squashfs snap files.
diff -Nru snapd-2.0.5/snap/squashfs/squashfs_test.go snapd-2.0.8/snap/squashfs/squashfs_test.go
--- snapd-2.0.5/snap/squashfs/squashfs_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/squashfs/squashfs_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -32,7 +32,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/osutil"
)
// Hook up check.v1 into the "go test" runner
diff -Nru snapd-2.0.5/snap/types.go snapd-2.0.8/snap/types.go
--- snapd-2.0.5/snap/types.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/types.go 2016-06-08 05:58:01.000000000 +0000
@@ -21,6 +21,7 @@
import (
"encoding/json"
+ "fmt"
)
// Type represents the kind of snap (app, core, gadget, os, kernel)
@@ -34,11 +35,6 @@
TypeKernel Type = "kernel"
)
-// MarshalJSON returns *m as the JSON encoding of m.
-func (m Type) MarshalJSON() ([]byte, error) {
- return json.Marshal(string(m))
-}
-
// UnmarshalJSON sets *m to a copy of data.
func (m *Type) UnmarshalJSON(data []byte) error {
var str string
@@ -46,13 +42,75 @@
return err
}
+ return m.fromString(str)
+}
+
+// UnmarshalYAML so ConfinementType implements yaml's Unmarshaler interface
+func (m *Type) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var str string
+ if err := unmarshal(&str); err != nil {
+ return err
+ }
+
+ return m.fromString(str)
+}
+
+// fromString converts str to Type and sets *m to it if validations pass
+func (m *Type) fromString(str string) error {
+ t := Type(str)
+
// this is a workaround as the store sends "application" but snappy uses
// "app" for TypeApp
if str == "application" {
- *m = TypeApp
- } else {
- *m = Type(str)
+ t = TypeApp
+ }
+
+ if t != TypeApp && t != TypeGadget && t != TypeOS && t != TypeKernel {
+ return fmt.Errorf("invalid snap type: %q", str)
+ }
+
+ *m = t
+
+ return nil
+}
+
+// ConfinementType represents the kind of confinement supported by the snap
+// (devmode only, or strict confinement)
+type ConfinementType string
+
+// The various confinement types we support
+const (
+ DevmodeConfinement ConfinementType = "devmode"
+ StrictConfinement ConfinementType = "strict"
+)
+
+// UnmarshalJSON sets *confinementType to a copy of data, assuming validation passes
+func (confinementType *ConfinementType) UnmarshalJSON(data []byte) error {
+ var s string
+ if err := json.Unmarshal(data, &s); err != nil {
+ return err
}
+ return confinementType.fromString(s)
+}
+
+// UnmarshalYAML so ConfinementType implements yaml's Unmarshaler interface
+func (confinementType *ConfinementType) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var s string
+ if err := unmarshal(&s); err != nil {
+ return err
+ }
+
+ return confinementType.fromString(s)
+}
+
+func (confinementType *ConfinementType) fromString(str string) error {
+ c := ConfinementType(str)
+ if c != DevmodeConfinement && c != StrictConfinement {
+ return fmt.Errorf("invalid confinement type: %q", str)
+ }
+
+ *confinementType = c
+
return nil
}
diff -Nru snapd-2.0.5/snap/types_test.go snapd-2.0.8/snap/types_test.go
--- snapd-2.0.5/snap/types_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/types_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -21,6 +21,8 @@
import (
"encoding/json"
+ "fmt"
+ "gopkg.in/yaml.v2"
. "gopkg.in/check.v1"
)
@@ -35,7 +37,7 @@
c.Assert(err, NotNil)
}
-func (s *typeSuite) TestMarshalTypes(c *C) {
+func (s *typeSuite) TestJsonMarshalTypes(c *C) {
out, err := json.Marshal(TypeApp)
c.Assert(err, IsNil)
c.Check(string(out), Equals, "\"app\"")
@@ -43,9 +45,17 @@
out, err = json.Marshal(TypeGadget)
c.Assert(err, IsNil)
c.Check(string(out), Equals, "\"gadget\"")
+
+ out, err = json.Marshal(TypeOS)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "\"os\"")
+
+ out, err = json.Marshal(TypeKernel)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "\"kernel\"")
}
-func (s *typeSuite) TestUnmarshalTypes(c *C) {
+func (s *typeSuite) TestJsonUnmarshalTypes(c *C) {
var st Type
err := json.Unmarshal([]byte("\"application\""), &st)
@@ -59,4 +69,136 @@
err = json.Unmarshal([]byte("\"gadget\""), &st)
c.Assert(err, IsNil)
c.Check(st, Equals, TypeGadget)
+
+ err = json.Unmarshal([]byte("\"os\""), &st)
+ c.Assert(err, IsNil)
+ c.Check(st, Equals, TypeOS)
+
+ err = json.Unmarshal([]byte("\"kernel\""), &st)
+ c.Assert(err, IsNil)
+ c.Check(st, Equals, TypeKernel)
+}
+
+func (s *typeSuite) TestJsonUnmarshalInvalidTypes(c *C) {
+ invalidTypes := []string{"foo", "-app", "gadget_"}
+ var st Type
+ for _, invalidType := range invalidTypes {
+ err := json.Unmarshal([]byte(fmt.Sprintf("%q", invalidType)), &st)
+ c.Assert(err, NotNil, Commentf("Expected '%s' to be an invalid type", invalidType))
+ }
+}
+
+func (s *typeSuite) TestYamlMarshalTypes(c *C) {
+ out, err := yaml.Marshal(TypeApp)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "app\n")
+
+ out, err = yaml.Marshal(TypeGadget)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "gadget\n")
+
+ out, err = yaml.Marshal(TypeOS)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "os\n")
+
+ out, err = yaml.Marshal(TypeKernel)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "kernel\n")
+}
+
+func (s *typeSuite) TestYamlUnmarshalTypes(c *C) {
+ var st Type
+
+ err := yaml.Unmarshal([]byte("application"), &st)
+ c.Assert(err, IsNil)
+ c.Check(st, Equals, TypeApp)
+
+ err = yaml.Unmarshal([]byte("app"), &st)
+ c.Assert(err, IsNil)
+ c.Check(st, Equals, TypeApp)
+
+ err = yaml.Unmarshal([]byte("gadget"), &st)
+ c.Assert(err, IsNil)
+ c.Check(st, Equals, TypeGadget)
+
+ err = yaml.Unmarshal([]byte("os"), &st)
+ c.Assert(err, IsNil)
+ c.Check(st, Equals, TypeOS)
+
+ err = yaml.Unmarshal([]byte("kernel"), &st)
+ c.Assert(err, IsNil)
+ c.Check(st, Equals, TypeKernel)
+}
+
+func (s *typeSuite) TestYamlUnmarshalInvalidTypes(c *C) {
+ invalidTypes := []string{"foo", "-app", "gadget_"}
+ var st Type
+ for _, invalidType := range invalidTypes {
+ err := yaml.Unmarshal([]byte(invalidType), &st)
+ c.Assert(err, NotNil, Commentf("Expected '%s' to be an invalid type", invalidType))
+ }
+}
+
+func (s *typeSuite) TestYamlMarshalConfinementTypes(c *C) {
+ out, err := yaml.Marshal(DevmodeConfinement)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "devmode\n")
+
+ out, err = yaml.Marshal(StrictConfinement)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "strict\n")
+}
+
+func (s *typeSuite) TestYamlUnmarshalConfinementTypes(c *C) {
+ var confinementType ConfinementType
+ err := yaml.Unmarshal([]byte("devmode"), &confinementType)
+ c.Assert(err, IsNil)
+ c.Check(confinementType, Equals, DevmodeConfinement)
+
+ err = yaml.Unmarshal([]byte("strict"), &confinementType)
+ c.Assert(err, IsNil)
+ c.Check(confinementType, Equals, StrictConfinement)
+}
+
+func (s *typeSuite) TestYamlUnmarshalInvalidConfinementTypes(c *C) {
+ var invalidConfinementTypes = []string{
+ "foo", "strict-", "_devmode",
+ }
+ var confinementType ConfinementType
+ for _, thisConfinementType := range invalidConfinementTypes {
+ err := yaml.Unmarshal([]byte(thisConfinementType), &confinementType)
+ c.Assert(err, NotNil, Commentf("Expected '%s' to be an invalid confinement type", thisConfinementType))
+ }
+}
+
+func (s *typeSuite) TestJsonMarshalConfinementTypes(c *C) {
+ out, err := json.Marshal(DevmodeConfinement)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "\"devmode\"")
+
+ out, err = json.Marshal(StrictConfinement)
+ c.Assert(err, IsNil)
+ c.Check(string(out), Equals, "\"strict\"")
+}
+
+func (s *typeSuite) TestJsonUnmarshalConfinementTypes(c *C) {
+ var confinementType ConfinementType
+ err := json.Unmarshal([]byte("\"devmode\""), &confinementType)
+ c.Assert(err, IsNil)
+ c.Check(confinementType, Equals, DevmodeConfinement)
+
+ err = json.Unmarshal([]byte("\"strict\""), &confinementType)
+ c.Assert(err, IsNil)
+ c.Check(confinementType, Equals, StrictConfinement)
+}
+
+func (s *typeSuite) TestJsonUnmarshalInvalidConfinementTypes(c *C) {
+ var invalidConfinementTypes = []string{
+ "foo", "strict-", "_devmode",
+ }
+ var confinementType ConfinementType
+ for _, thisConfinementType := range invalidConfinementTypes {
+ err := json.Unmarshal([]byte(fmt.Sprintf("%q", thisConfinementType)), &confinementType)
+ c.Assert(err, NotNil, Commentf("Expected '%s' to be an invalid confinement type", thisConfinementType))
+ }
}
diff -Nru snapd-2.0.5/snap/validate.go snapd-2.0.8/snap/validate.go
--- snapd-2.0.5/snap/validate.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/validate.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,6 +26,8 @@
// Regular expression describing correct identifiers.
var validName = regexp.MustCompile("^[a-z](?:-?[a-z0-9])*$")
+var validEpoch = regexp.MustCompile("^(?:0|[1-9][0-9]*[*]?)$")
+var validHookName = regexp.MustCompile(`^[a-z](?:-?[a-z])*$`)
// ValidateName checks if a string can be used as a snap name.
func ValidateName(name string) error {
@@ -36,6 +38,24 @@
return nil
}
+// ValidateEpoch checks if a string can be used as a snap epoch.
+func ValidateEpoch(epoch string) error {
+ valid := validEpoch.MatchString(epoch)
+ if !valid {
+ return fmt.Errorf("invalid snap epoch: %q", epoch)
+ }
+ return nil
+}
+
+// ValidateHook validates the content of the given HookInfo
+func ValidateHook(hook *HookInfo) error {
+ valid := validHookName.MatchString(hook.Name)
+ if !valid {
+ return fmt.Errorf("invalid hook name: %q", hook.Name)
+ }
+ return nil
+}
+
// Validate verifies the content in the info.
func Validate(info *Info) error {
name := info.Name()
@@ -47,6 +67,15 @@
return err
}
+ epoch := info.Epoch
+ if epoch == "" {
+ return fmt.Errorf("snap epoch cannot be empty")
+ }
+ err = ValidateEpoch(epoch)
+ if err != nil {
+ return err
+ }
+
// validate app entries
for _, app := range info.Apps {
err := ValidateApp(app)
@@ -54,6 +83,14 @@
return err
}
}
+
+ // validate hook entries
+ for _, hook := range info.Hooks {
+ err := ValidateHook(hook)
+ if err != nil {
+ return err
+ }
+ }
return nil
}
@@ -68,6 +105,7 @@
// appContentWhitelist is the whitelist of legal chars in the "apps"
// section of snap.yaml
var appContentWhitelist = regexp.MustCompile(`^[A-Za-z0-9/. _#:-]*$`)
+var validAppName = regexp.MustCompile("^[a-zA-Z0-9](?:-?[a-zA-Z0-9])*$")
// ValidateApp verifies the content in the app info.
func ValidateApp(app *AppInfo) error {
@@ -78,8 +116,13 @@
return fmt.Errorf(`"daemon" field contains invalid value %q`, app.Daemon)
}
+ // Validate app name
+ if !validAppName.MatchString(app.Name) {
+ return fmt.Errorf("cannot have %q as app name - use letters, digits, and dash as separator", app.Name)
+ }
+
+ // Validate the rest of the app info
checks := map[string]string{
- "name": app.Name,
"command": app.Command,
"stop-command": app.StopCommand,
"post-stop-command": app.PostStopCommand,
diff -Nru snapd-2.0.5/snap/validate_test.go snapd-2.0.8/snap/validate_test.go
--- snapd-2.0.5/snap/validate_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snap/validate_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/snap"
+ . "github.com/snapcore/snapd/snap"
)
type ValidateSuite struct{}
@@ -61,35 +61,99 @@
}
}
+func (s *ValidateSuite) TestValidateEpoch(c *C) {
+ validEpochs := []string{
+ "0", "1*", "1", "400*", "1234",
+ }
+ for _, epoch := range validEpochs {
+ err := ValidateEpoch(epoch)
+ c.Assert(err, IsNil)
+ }
+ invalidEpochs := []string{
+ "0*", "_", "1-", "1+", "-1", "+1", "-1*", "a", "1a", "1**",
+ }
+ for _, epoch := range invalidEpochs {
+ err := ValidateEpoch(epoch)
+ c.Assert(err, ErrorMatches, `invalid snap epoch: ".*"`)
+ }
+}
+
+func (s *ValidateSuite) TestValidateHook(c *C) {
+ validHooks := []*HookInfo{
+ &HookInfo{Name: "a"},
+ &HookInfo{Name: "aaa"},
+ &HookInfo{Name: "a-a"},
+ &HookInfo{Name: "aa-a"},
+ &HookInfo{Name: "a-aa"},
+ &HookInfo{Name: "a-b-c"},
+ }
+ for _, hook := range validHooks {
+ err := ValidateHook(hook)
+ c.Assert(err, IsNil)
+ }
+ invalidHooks := []*HookInfo{
+ &HookInfo{Name: ""},
+ &HookInfo{Name: "a a"},
+ &HookInfo{Name: "a--a"},
+ &HookInfo{Name: "-a"},
+ &HookInfo{Name: "a-"},
+ &HookInfo{Name: "0"},
+ &HookInfo{Name: "123"},
+ &HookInfo{Name: "abc0"},
+ &HookInfo{Name: "日本語"},
+ }
+ for _, hook := range invalidHooks {
+ err := ValidateHook(hook)
+ c.Assert(err, ErrorMatches, `invalid hook name: ".*"`)
+ }
+}
+
// ValidateApp
+func (s *ValidateSuite) TestValidateAppName(c *C) {
+ validAppNames := []string{
+ "1", "a", "aa", "aaa", "aaaa", "Aa", "aA", "1a", "a1", "1-a", "a-1",
+ "a-a", "aa-a", "a-aa", "a-b-c", "0a-a", "a-0a",
+ }
+ for _, name := range validAppNames {
+ c.Check(ValidateApp(&AppInfo{Name: name}), IsNil)
+ }
+ invalidAppNames := []string{
+ "", "-", "--", "a--a", "a-", "a ", " a", "a a", "日本語", "한글",
+ "ру́сский язы́к", "ໄຂ່ອີສເຕີ້", ":a", "a:", "a:a", "_a", "a_", "a_a",
+ }
+ for _, name := range invalidAppNames {
+ err := ValidateApp(&AppInfo{Name: name})
+ c.Assert(err, ErrorMatches, `cannot have ".*" as app name.*`)
+ }
+}
+
func (s *ValidateSuite) TestAppWhitelistSimple(c *C) {
- c.Check(ValidateApp(&AppInfo{Name: "foo"}), IsNil)
- c.Check(ValidateApp(&AppInfo{Command: "foo"}), IsNil)
- c.Check(ValidateApp(&AppInfo{StopCommand: "foo"}), IsNil)
- c.Check(ValidateApp(&AppInfo{PostStopCommand: "foo"}), IsNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", Command: "foo"}), IsNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", StopCommand: "foo"}), IsNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", PostStopCommand: "foo"}), IsNil)
}
func (s *ValidateSuite) TestAppWhitelistIllegal(c *C) {
c.Check(ValidateApp(&AppInfo{Name: "x\n"}), NotNil)
c.Check(ValidateApp(&AppInfo{Name: "test!me"}), NotNil)
- c.Check(ValidateApp(&AppInfo{Command: "foo\n"}), NotNil)
- c.Check(ValidateApp(&AppInfo{StopCommand: "foo\n"}), NotNil)
- c.Check(ValidateApp(&AppInfo{PostStopCommand: "foo\n"}), NotNil)
- c.Check(ValidateApp(&AppInfo{SocketMode: "foo\n"}), NotNil)
- c.Check(ValidateApp(&AppInfo{ListenStream: "foo\n"}), NotNil)
- c.Check(ValidateApp(&AppInfo{BusName: "foo\n"}), NotNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", Command: "foo\n"}), NotNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", StopCommand: "foo\n"}), NotNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", PostStopCommand: "foo\n"}), NotNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", SocketMode: "foo\n"}), NotNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", ListenStream: "foo\n"}), NotNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", BusName: "foo\n"}), NotNil)
}
func (s *ValidateSuite) TestAppDaemonValue(c *C) {
- c.Check(ValidateApp(&AppInfo{Daemon: "oneshot"}), IsNil)
- c.Check(ValidateApp(&AppInfo{Daemon: "nono"}), ErrorMatches, `"daemon" field contains invalid value "nono"`)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", Daemon: "oneshot"}), IsNil)
+ c.Check(ValidateApp(&AppInfo{Name: "foo", Daemon: "nono"}), ErrorMatches, `"daemon" field contains invalid value "nono"`)
}
func (s *ValidateSuite) TestAppWhitelistError(c *C) {
- err := ValidateApp(&AppInfo{Name: "x\n"})
+ err := ValidateApp(&AppInfo{Name: "foo", Command: "x\n"})
c.Assert(err, NotNil)
- c.Check(err.Error(), Equals, `app description field 'name' contains illegal "x\n" (legal: '^[A-Za-z0-9/. _#:-]*$')`)
+ c.Check(err.Error(), Equals, `app description field 'command' contains illegal "x\n" (legal: '^[A-Za-z0-9/. _#:-]*$')`)
}
// Validate
@@ -140,3 +204,34 @@
err = Validate(info)
c.Check(err, ErrorMatches, `snap name cannot be empty`)
}
+
+func (s *ValidateSuite) TestIllegalSnapEpoch(c *C) {
+ info, err := InfoFromSnapYaml([]byte(`name: foo
+version: 1.0
+epoch: 0*
+`))
+ c.Assert(err, IsNil)
+
+ err = Validate(info)
+ c.Check(err, ErrorMatches, `invalid snap epoch: "0\*"`)
+}
+
+func (s *ValidateSuite) TestMissingSnapEpochIsOkay(c *C) {
+ info, err := InfoFromSnapYaml([]byte(`name: foo
+version: 1.0
+`))
+ c.Assert(err, IsNil)
+ c.Assert(Validate(info), IsNil)
+}
+
+func (s *ValidateSuite) TestIllegalHookName(c *C) {
+ info, err := InfoFromSnapYaml([]byte(`name: foo
+version: 1.0
+hooks:
+ abc123:
+`))
+ c.Assert(err, IsNil)
+
+ err = Validate(info)
+ c.Check(err, ErrorMatches, `invalid hook name: "abc123"`)
+}
diff -Nru snapd-2.0.5/snappy/common_test.go snapd-2.0.8/snappy/common_test.go
--- snapd-2.0.5/snappy/common_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/common_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -29,9 +29,9 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
)
const (
@@ -71,7 +71,7 @@
if err != nil {
return "", err
}
- info.SideInfo = snap.SideInfo{Revision: revno}
+ info.SideInfo = snap.SideInfo{Revision: snap.R(revno)}
metaDir := filepath.Join(info.MountDir(), "meta")
if err := os.MkdirAll(metaDir, 0775); err != nil {
@@ -84,7 +84,7 @@
si := snap.SideInfo{
OfficialName: info.Name(),
- Revision: revno,
+ Revision: snap.R(revno),
Developer: testDeveloper,
Channel: "remote-channel",
EditedSummary: "hello in summary",
@@ -177,20 +177,20 @@
foo10 := &snap.SideInfo{
OfficialName: "foo",
Developer: testDeveloper,
- Revision: 100,
+ Revision: snap.R(100),
Channel: "remote-channel",
}
- info1, err := (&Overlord{}).InstallWithSideInfo(snapPath, foo10, AllowUnauthenticated|AllowGadget, inter)
+ info1, err := (&Overlord{}).InstallWithSideInfo(snapPath, foo10, LegacyAllowUnauthenticated|LegacyAllowGadget, inter)
c.Assert(err, IsNil)
snapPath = makeTestSnapPackage(c, snapYamlContent+"version: 2.0")
foo20 := &snap.SideInfo{
OfficialName: "foo",
Developer: testDeveloper,
- Revision: 200,
+ Revision: snap.R(200),
Channel: "remote-channel",
}
- info2, err := (&Overlord{}).InstallWithSideInfo(snapPath, foo20, AllowUnauthenticated|AllowGadget, inter)
+ info2, err := (&Overlord{}).InstallWithSideInfo(snapPath, foo20, LegacyAllowUnauthenticated|LegacyAllowGadget, inter)
c.Assert(err, IsNil)
installed, err := (&Overlord{}).Installed()
diff -Nru snapd-2.0.5/snappy/desktop_test.go snapd-2.0.8/snappy/desktop_test.go
--- snapd-2.0.5/snappy/desktop_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/desktop_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
)
var desktopAppYaml = `
@@ -62,7 +62,7 @@
c.Assert(string(content), Matches, "(?s).*Name=foo\n.*")
// unlink (deactivate) removes it again
- err = UnlinkSnap(snap.Info(), nil)
+ err = unlinkSnap(snap.Info(), nil)
c.Assert(err, IsNil)
c.Assert(osutil.FileExists(mockDesktopFilePath), Equals, false)
}
diff -Nru snapd-2.0.5/snappy/errors.go snapd-2.0.8/snappy/errors.go
--- snapd-2.0.5/snappy/errors.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/errors.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
"fmt"
"strings"
- "github.com/ubuntu-core/snappy/arch"
+ "github.com/snapcore/snapd/arch"
)
var (
diff -Nru snapd-2.0.5/snappy/firstboot.go snapd-2.0.8/snappy/firstboot.go
--- snapd-2.0.5/snappy/firstboot.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/firstboot.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,9 +26,9 @@
"os/exec"
"path/filepath"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/progress"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/progress"
"gopkg.in/yaml.v2"
)
diff -Nru snapd-2.0.5/snappy/firstboot_test.go snapd-2.0.8/snappy/firstboot_test.go
--- snapd-2.0.5/snappy/firstboot_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/firstboot_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/systemd"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/systemd"
)
type FirstBootTestSuite struct {
diff -Nru snapd-2.0.5/snappy/gadget.go snapd-2.0.8/snappy/gadget.go
--- snapd-2.0.5/snappy/gadget.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/gadget.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,42 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-
-/*
- * Copyright (C) 2014-2015 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-// TODO this should be it's own package, but depends on splitting out
-// snap.yaml's
-
-package snappy
-
-import (
- "errors"
-
- "github.com/ubuntu-core/snappy/snap"
-)
-
-// getGadget is a convenience function to not go into the details for
-// the business logic for a gadget package in every other function
-var getGadget = getGadgetImpl
-
-func getGadgetImpl() (*snap.Info, error) {
- gadgets, _ := ActiveSnapsByType(snap.TypeGadget)
- if len(gadgets) == 1 {
- return gadgets[0].Info(), nil
- }
-
- return nil, errors.New("no gadget snap")
-}
diff -Nru snapd-2.0.5/snappy/info.go snapd-2.0.8/snappy/info.go
--- snapd-2.0.5/snappy/info.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/info.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,10 +27,10 @@
"gopkg.in/yaml.v2"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
)
const (
@@ -159,7 +159,7 @@
// FindSnapsByNameAndRevision returns the snaps with the name/version in the
// given slice of snaps
-func FindSnapsByNameAndRevision(needle string, revision int, haystack []*Snap) []*Snap {
+func FindSnapsByNameAndRevision(needle string, revision snap.Revision, haystack []*Snap) []*Snap {
name, developer := SplitDeveloper(needle)
ignorens := developer == ""
var found []*Snap
@@ -199,14 +199,14 @@
}
// manifestPath returns the would be path for the snap manifest.
-func manifestPath(name string, revno int) string {
- return filepath.Join(dirs.SnapMetaDir, fmt.Sprintf("%s_%d.manifest", name, revno))
+func manifestPath(name string, revno snap.Revision) string {
+ return filepath.Join(dirs.SnapMetaDir, fmt.Sprintf("%s_%s.manifest", name, revno.String()))
}
// SaveManifest saves the manifest at the designated location for the snap containing information not in the snap.yaml.
func SaveManifest(rsnap *snap.Info) error {
- if rsnap.Revision == 0 {
- return fmt.Errorf("internal error: should not be storring manifests for sideloaded snaps")
+ if !rsnap.Revision.Store() {
+ return fmt.Errorf("internal error: should not be storing manifests for local snaps")
}
// XXX: we store OfficialName though it may not be the blessed one later
diff -Nru snapd-2.0.5/snappy/info_test.go snapd-2.0.8/snappy/info_test.go
--- snapd-2.0.5/snappy/info_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/info_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,8 +26,8 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
)
func (s *SnapTestSuite) TestActiveSnapByType(c *C) {
@@ -85,7 +85,7 @@
// now remove the channel
si := snap.SideInfo{
OfficialName: "app",
- Revision: 11,
+ Revision: snap.R(11),
Developer: testDeveloper,
Channel: "",
EditedSummary: "hello",
@@ -165,7 +165,7 @@
c.Assert(ActivateSnap(snap, ag), IsNil)
c.Check(PackageNameActive("hello-snap"), Equals, true)
- c.Assert(UnlinkSnap(snap.Info(), ag), IsNil)
+ c.Assert(unlinkSnap(snap.Info(), ag), IsNil)
c.Check(PackageNameActive("hello-snap"), Equals, false)
}
@@ -217,19 +217,19 @@
installed, err := repo.Installed()
c.Assert(err, IsNil)
- snaps := FindSnapsByNameAndRevision("hello-snap."+testDeveloper, 11, installed)
+ snaps := FindSnapsByNameAndRevision("hello-snap."+testDeveloper, snap.R(11), installed)
c.Check(snaps, HasLen, 1)
- snaps = FindSnapsByNameAndRevision("bad-app."+testDeveloper, 11, installed)
+ snaps = FindSnapsByNameAndRevision("bad-app."+testDeveloper, snap.R(11), installed)
c.Check(snaps, HasLen, 0)
- snaps = FindSnapsByNameAndRevision("hello-snap.badDeveloper", 11, installed)
+ snaps = FindSnapsByNameAndRevision("hello-snap.badDeveloper", snap.R(11), installed)
c.Check(snaps, HasLen, 0)
- snaps = FindSnapsByNameAndRevision("hello-snap."+testDeveloper, 22, installed)
+ snaps = FindSnapsByNameAndRevision("hello-snap."+testDeveloper, snap.R(22), installed)
c.Check(snaps, HasLen, 0)
- snaps = FindSnapsByNameAndRevision("hello-snap", 11, installed)
+ snaps = FindSnapsByNameAndRevision("hello-snap", snap.R(11), installed)
c.Check(snaps, HasLen, 1)
- snaps = FindSnapsByNameAndRevision("bad-app", 11, installed)
+ snaps = FindSnapsByNameAndRevision("bad-app", snap.R(11), installed)
c.Check(snaps, HasLen, 0)
- snaps = FindSnapsByNameAndRevision("hello-snap", 22, installed)
+ snaps = FindSnapsByNameAndRevision("hello-snap", snap.R(22), installed)
c.Check(snaps, HasLen, 0)
}
diff -Nru snapd-2.0.5/snappy/install.go snapd-2.0.8/snappy/install.go
--- snapd-2.0.5/snappy/install.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/install.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,31 +24,31 @@
"os"
"sort"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/provisioning"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/store"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/provisioning"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/store"
)
// SetupFlags can be used to pass additional flags to the install of a
// snap
-type InstallFlags uint
+type LegacyInstallFlags uint
const (
// AllowUnauthenticated allows to install a snap even if it cannot be authenticated
- AllowUnauthenticated InstallFlags = 1 << iota
+ LegacyAllowUnauthenticated LegacyInstallFlags = 1 << iota
// InhibitHooks will ensure that the hooks are not run
- InhibitHooks
+ LegacyInhibitHooks
// DoInstallGC will ensure that garbage collection is done
- DoInstallGC
+ LegacyDoInstallGC
// AllowGadget allows the installation of Gadget packages, this does not affect updates.
- AllowGadget
- // DeveloperMode will install the snap without confinement
- DeveloperMode
+ LegacyAllowGadget
+
+ // Do not add new flags here! this is all going away soon! just kept alive as long as we may need to quickly patch up u-d-f.
+ DO_NOT_ADD_NEW_FLAGS_HERE
)
-func installRemote(mStore *store.SnapUbuntuStoreRepository, remoteSnap *snap.Info, flags InstallFlags, meter progress.Meter) (string, error) {
+func installRemote(mStore *store.SnapUbuntuStoreRepository, remoteSnap *snap.Info, flags LegacyInstallFlags, meter progress.Meter) (string, error) {
downloadedSnap, err := mStore.Download(remoteSnap, meter, nil)
if err != nil {
return "", fmt.Errorf("cannot download %s: %s", remoteSnap.Name(), err)
@@ -63,82 +63,12 @@
return localSnap.Name(), nil
}
-func doUpdate(mStore *store.SnapUbuntuStoreRepository, rsnap *snap.Info, flags InstallFlags, meter progress.Meter) error {
- _, err := installRemote(mStore, rsnap, flags, meter)
- if err == ErrSideLoaded {
- logger.Noticef("Skipping sideloaded package: %s", rsnap.Name())
- return nil
- } else if err != nil {
- return err
- }
-
- if err := GarbageCollect(rsnap.Name(), flags, meter); err != nil {
- return err
- }
-
- return nil
-}
-
-// FIXME: This needs to go (and will go). We will have something
-// like:
-// remoteSnapType = GetUpdatesFromServer()
-// localSnapType = DoUpdate(remoteSnaps)
-// ShowUpdates(localSnaps)
-// By using the different types (instead of the same interface)
-// it will not be possilbe to pass remote snaps into the
-// ShowUpdates() output.
-//
-//
-// convertToInstalledSnaps takes a slice of remote snaps that got
-// updated and returns the corresponding local snaps
-func convertToInstalledSnaps(remoteUpdates []*snap.Info) ([]*Snap, error) {
- installed, err := (&Overlord{}).Installed()
- if err != nil {
- return nil, err
- }
-
- installedUpdates := make([]*Snap, 0, len(remoteUpdates))
- for _, snap := range remoteUpdates {
- for _, installed := range installed {
- if snap.Name() == installed.Name() && snap.Version == installed.Version() {
- installedUpdates = append(installedUpdates, installed)
- }
- }
- }
-
- return installedUpdates, nil
-}
-
-// snapUpdates identifies which snaps have updates in the store.
-func snapUpdates(repo *store.SnapUbuntuStoreRepository) (snaps []*snap.Info, err error) {
- // TODO: this should eventually be snap-id based
- // NOTE this *will* send .sideload apps to the store.
- installed, err := ActiveSnapIterByType(fullNameWithChannel, snap.TypeApp, snap.TypeGadget, snap.TypeOS, snap.TypeKernel)
- if err != nil || len(installed) == 0 {
- return nil, err
- }
-
- rsnaps, err := repo.Updates(installed, nil)
- if err != nil {
- return nil, err
- }
-
- for _, rsnap := range rsnaps {
- current := ActiveSnapByName(rsnap.Name())
- if current == nil || current.Revision() != rsnap.Revision {
- snaps = append(snaps, rsnap)
- }
- }
-
- return snaps, nil
-}
-
var storeConfig = (*store.SnapUbuntuStoreConfig)(nil)
// TODO: kill this function once fewer places make a store on the fly
-// NewConfiguredUbuntuStoreSnapRepository creates a new fully configured store.SnapUbuntuStoreRepository with the store id selected by the gadget.
-func NewConfiguredUbuntuStoreSnapRepository() *store.SnapUbuntuStoreRepository {
+// newConfiguredUbuntuStoreSnapRepository creates a new fully configured store.SnapUbuntuStoreRepository with the store id selected by the gadget.
+func newConfiguredUbuntuStoreSnapRepository() *store.SnapUbuntuStoreRepository {
storeID := ""
// TODO: set the store-id here from the model information
if cand := os.Getenv("UBUNTU_STORE_ID"); cand != "" {
@@ -148,75 +78,9 @@
return store.NewUbuntuStoreSnapRepository(storeConfig, storeID)
}
-// Update updates the selected name
-func Update(name string, flags InstallFlags, meter progress.Meter) ([]*Snap, error) {
- installed, err := (&Overlord{}).Installed()
- if err != nil {
- return nil, err
- }
- cur := FindSnapsByName(name, installed)
- if len(cur) != 1 {
- return nil, ErrNotInstalled
- }
-
- mStore := NewConfiguredUbuntuStoreSnapRepository()
- // zomg :-(
- // TODO: query the store for just this package, instead of this
- updates, err := snapUpdates(mStore)
- if err != nil {
- return nil, fmt.Errorf("cannot get updates: %s", err)
- }
- var update *snap.Info
- for _, upd := range updates {
- if cur[0].Name() == upd.Name() {
- update = upd
- break
- }
- }
- if update == nil {
- return nil, fmt.Errorf("cannot find any update for %q", name)
- }
-
- if err := doUpdate(mStore, update, flags, meter); err != nil {
- return nil, err
- }
-
- installedUpdates, err := convertToInstalledSnaps([]*snap.Info{update})
- if err != nil {
- return nil, err
- }
-
- return installedUpdates, nil
-}
-
-// UpdateAll the installed snappy packages, it returns the updated Snaps
-// if updates where available and an error and nil if any of the updates
-// fail to apply.
-func UpdateAll(flags InstallFlags, meter progress.Meter) ([]*Snap, error) {
- mStore := NewConfiguredUbuntuStoreSnapRepository()
- updates, err := snapUpdates(mStore)
- if err != nil {
- return nil, err
- }
-
- for _, snap := range updates {
- meter.Notify(fmt.Sprintf("Updating %s (%s)", snap.Name(), snap.Version))
- if err := doUpdate(mStore, snap, flags, meter); err != nil {
- return nil, err
- }
- }
-
- installedUpdates, err := convertToInstalledSnaps(updates)
- if err != nil {
- return nil, err
- }
-
- return installedUpdates, nil
-}
-
// Install the givens snap names provided via args. This can be local
// files or snaps that are queried from the store
-func Install(name, channel string, flags InstallFlags, meter progress.Meter) (string, error) {
+func Install(name, channel string, flags LegacyInstallFlags, meter progress.Meter) (string, error) {
name, err := doInstall(name, channel, flags, meter)
if err != nil {
return "", err
@@ -225,7 +89,7 @@
return name, GarbageCollect(name, flags, meter)
}
-func doInstall(name, channel string, flags InstallFlags, meter progress.Meter) (snapName string, err error) {
+func doInstall(name, channel string, flags LegacyInstallFlags, meter progress.Meter) (snapName string, err error) {
defer func() {
if err != nil {
err = &ErrInstallFailed{Snap: name, OrigErr: err}
@@ -237,7 +101,7 @@
// we allow unauthenticated package when in developer
// mode
if provisioning.InDeveloperMode() {
- flags |= AllowUnauthenticated
+ flags |= LegacyAllowUnauthenticated
}
snap, err := (&Overlord{}).Install(name, flags, meter)
@@ -249,7 +113,7 @@
}
// check repos next
- mStore := NewConfiguredUbuntuStoreSnapRepository()
+ mStore := newConfiguredUbuntuStoreSnapRepository()
installed, err := (&Overlord{}).Installed()
if err != nil {
return "", err
@@ -274,10 +138,10 @@
// GarbageCollect removes all versions two older than the current active
// version, as long as NeedsReboot() is false on all the versions found, and
// DoInstallGC is set.
-func GarbageCollect(name string, flags InstallFlags, pb progress.Meter) error {
+func GarbageCollect(name string, flags LegacyInstallFlags, pb progress.Meter) error {
var snaps BySnapVersion
- if (flags & DoInstallGC) == 0 {
+ if (flags & LegacyDoInstallGC) == 0 {
return nil
}
diff -Nru snapd-2.0.5/snappy/install_test.go snapd-2.0.8/snappy/install_test.go
--- snapd-2.0.5/snappy/install_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/install_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -31,13 +31,13 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/progress"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/progress"
)
func (s *SnapTestSuite) TestInstallInstall(c *C) {
snapPath := makeTestSnapPackage(c, "")
- name, err := Install(snapPath, "channel", AllowUnauthenticated|DoInstallGC, &progress.NullProgress{})
+ name, err := Install(snapPath, "channel", LegacyAllowUnauthenticated|LegacyDoInstallGC, &progress.NullProgress{})
c.Assert(err, IsNil)
c.Check(name, Equals, "foo")
@@ -51,7 +51,7 @@
func (s *SnapTestSuite) TestInstallNoHook(c *C) {
snapPath := makeTestSnapPackage(c, "")
- name, err := Install(snapPath, "", AllowUnauthenticated|DoInstallGC|InhibitHooks, &progress.NullProgress{})
+ name, err := Install(snapPath, "", LegacyAllowUnauthenticated|LegacyDoInstallGC|LegacyInhibitHooks, &progress.NullProgress{})
c.Assert(err, IsNil)
c.Check(name, Equals, "foo")
@@ -63,7 +63,7 @@
c.Check(snap.IsActive(), Equals, false) // c.f. TestInstallInstall
}
-func (s *SnapTestSuite) installThree(c *C, flags InstallFlags) {
+func (s *SnapTestSuite) installThree(c *C, flags LegacyInstallFlags) {
c.Skip("can't really install 3 separate snap version just through the old snappy.Install interface, they all get revision 0!")
dirs.SnapDataHomeGlob = filepath.Join(s.tempdir, "home", "*", "snaps")
homeDir := filepath.Join(s.tempdir, "home", "user1", "snaps")
@@ -88,7 +88,7 @@
// check that on install we remove all but the two newest package versions
func (s *SnapTestSuite) TestClickInstallGCSimple(c *C) {
- s.installThree(c, AllowUnauthenticated|DoInstallGC)
+ s.installThree(c, LegacyAllowUnauthenticated|LegacyDoInstallGC)
globs, err := filepath.Glob(filepath.Join(dirs.SnapSnapsDir, "foo", "*"))
c.Check(err, IsNil)
@@ -111,7 +111,7 @@
// check that if flags does not include DoInstallGC, no gc is done
func (s *SnapTestSuite) TestClickInstallGCSuppressed(c *C) {
- s.installThree(c, AllowUnauthenticated)
+ s.installThree(c, LegacyAllowUnauthenticated)
globs, err := filepath.Glob(filepath.Join(dirs.SnapSnapsDir, "foo", "*"))
c.Assert(err, IsNil)
@@ -213,79 +213,3 @@
_, err = Install("hello-snap", "ch", 0, ag)
c.Assert(err, ErrorMatches, ".*"+ErrPackageNameAlreadyInstalled.Error())
}
-
-func (s *SnapTestSuite) TestUpdate(c *C) {
- yamlPath, err := makeInstalledMockSnap("name: foo\nversion: 1", 25)
- c.Assert(err, IsNil)
- makeSnapActive(yamlPath)
- installed, err := (&Overlord{}).Installed()
- c.Assert(err, IsNil)
- c.Assert(installed, HasLen, 1)
- c.Assert(ActiveSnapByName("foo"), NotNil)
-
- snapPackagev2 := makeTestSnapPackage(c, "name: foo\nversion: 2")
-
- snapR, err := os.Open(snapPackagev2)
- c.Assert(err, IsNil)
- defer snapR.Close()
-
- // details
- var dlURL, iconURL string
- mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- switch r.URL.Path {
- case "/search":
- io.WriteString(w, `{"_embedded": {"clickindex:package": [{
-"package_name": "foo",
-"version": "2",
-"revision": 27,
-"developer": "`+testDeveloper+`",
-"anon_download_url": "`+dlURL+`",
-"icon_url": "`+iconURL+`"
-}]}}`)
- case "/dl":
- snapR.Seek(0, 0)
- io.Copy(w, snapR)
- case "/icon":
- fmt.Fprintf(w, "")
- default:
- panic("unexpected url path: " + r.URL.Path)
- }
- }))
- c.Assert(mockServer, NotNil)
- defer mockServer.Close()
-
- dlURL = mockServer.URL + "/dl"
- iconURL = mockServer.URL + "/icon"
-
- s.storeCfg.SearchURI, err = url.Parse(mockServer.URL + "/search")
- c.Assert(err, IsNil)
-
- // bulk
- mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, `[{
- "package_name": "foo",
- "version": "2",
- "revision": 3,
- "origin": "`+testDeveloper+`",
- "anon_download_url": "`+dlURL+`",
- "download_url": "`+dlURL+`",
- "icon_url": "`+iconURL+`"
-}]`)
- }))
-
- s.storeCfg.BulkURI, err = url.Parse(mockServer.URL)
- c.Assert(err, IsNil)
-
- c.Assert(mockServer, NotNil)
- defer mockServer.Close()
-
- // the test
- updates, err := UpdateAll(0, &progress.NullProgress{})
- c.Assert(err, IsNil)
- c.Assert(updates, HasLen, 1)
- c.Check(updates[0].Name(), Equals, "foo")
- c.Check(updates[0].Version(), Equals, "2")
- c.Check(updates[0].Revision(), Equals, 3)
- // ensure that we get a "local" snap back - not a remote one
- c.Check(updates[0], FitsTypeOf, &Snap{})
-}
diff -Nru snapd-2.0.5/snappy/kernel_os.go snapd-2.0.8/snappy/kernel_os.go
--- snapd-2.0.5/snappy/kernel_os.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/kernel_os.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,14 +24,14 @@
"os"
"os/exec"
"path/filepath"
- "strconv"
"strings"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/partition"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/partition"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
)
// override in tests
@@ -65,7 +65,7 @@
// extractKernelAssets extracts kernel/initrd/dtb data from the given
// Snap to a versionized bootloader directory so that the bootloader
// can use it.
-func extractKernelAssets(s *snap.Info, snapf snap.File, flags InstallFlags, inter progress.Meter) error {
+func extractKernelAssets(s *snap.Info, flags LegacyInstallFlags, inter progress.Meter) error {
if s.Type != snap.TypeKernel {
return fmt.Errorf("cannot extract kernel assets from snap type %q", s.Type)
}
@@ -122,6 +122,9 @@
// SetNextBoot will schedule the given os or kernel snap to be used in
// the next boot
func SetNextBoot(s *snap.Info) error {
+ if release.OnClassic {
+ return nil
+ }
if s.Type != snap.TypeOS && s.Type != snap.TypeKernel {
return nil
}
@@ -188,14 +191,14 @@
return false
}
-func nameAndRevnoFromSnap(snap string) (string, int) {
- name := strings.Split(snap, "_")[0]
- revnoNSuffix := strings.Split(snap, "_")[1]
- revno, err := strconv.Atoi(strings.Split(revnoNSuffix, ".snap")[0])
+func nameAndRevnoFromSnap(sn string) (string, snap.Revision) {
+ name := strings.Split(sn, "_")[0]
+ revnoNSuffix := strings.Split(sn, "_")[1]
+ rev, err := snap.ParseRevision(strings.Split(revnoNSuffix, ".snap")[0])
if err != nil {
- return "", -1
+ return "", snap.Revision{}
}
- return name, revno
+ return name, rev
}
// SyncBoot synchronizes the active kernel and OS snap versions with
@@ -206,6 +209,9 @@
// misleading. This code will check what kernel/os booted and set
// those versions active.
func SyncBoot() error {
+ if release.OnClassic {
+ return nil
+ }
bootloader, err := findBootloader()
if err != nil {
return fmt.Errorf("cannot run SyncBoot: %s", err)
@@ -224,7 +230,7 @@
name, revno := nameAndRevnoFromSnap(snap)
found := FindSnapsByNameAndRevision(name, revno, installed)
if len(found) != 1 {
- return fmt.Errorf("cannot SyncBoot, expected 1 snap %q (revno=%d) found %d", snap, revno, len(found))
+ return fmt.Errorf("cannot SyncBoot, expected 1 snap %q (revision %s) found %d", snap, revno, len(found))
}
if err := overlord.SetActive(found[0], true, nil); err != nil {
return fmt.Errorf("cannot SyncBoot, cannot make %s active: %s", found[0].Name(), err)
diff -Nru snapd-2.0.5/snappy/kernel_os_test.go snapd-2.0.8/snappy/kernel_os_test.go
--- snapd-2.0.5/snappy/kernel_os_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/kernel_os_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,8 +20,11 @@
package snappy
import (
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/partition"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/partition"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
. "gopkg.in/check.v1"
)
@@ -43,11 +46,11 @@
func (s *kernelTestSuite) TestNameAndRevnoFromSnap(c *C) {
name, revno := nameAndRevnoFromSnap("canonical-pc-linux.canonical_101.snap")
c.Check(name, Equals, "canonical-pc-linux.canonical")
- c.Check(revno, Equals, 101)
+ c.Check(revno, Equals, snap.R(101))
name, revno = nameAndRevnoFromSnap("ubuntu-core.canonical_103.snap")
c.Check(name, Equals, "ubuntu-core.canonical")
- c.Check(revno, Equals, 103)
+ c.Check(revno, Equals, snap.R(103))
}
var kernelYaml = `name: linux
@@ -59,6 +62,9 @@
`
func (s *kernelTestSuite) TestSyncBoot(c *C) {
+ restore := release.MockOnClassic(false)
+ defer restore()
+
// make an OS
_, err := makeInstalledMockSnap(osYaml+"version: v1", 10)
c.Assert(err, IsNil)
@@ -77,10 +83,10 @@
c.Assert(err, IsNil)
c.Assert(installed, HasLen, 3)
// ensure that v2 is the active one
- found := FindSnapsByNameAndRevision("linux", 21, installed)
+ found := FindSnapsByNameAndRevision("linux", snap.R(21), installed)
c.Assert(found, HasLen, 1)
c.Assert(found[0].Name(), Equals, "linux")
- c.Assert(found[0].Revision(), Equals, 21)
+ c.Assert(found[0].Revision(), Equals, snap.R(21))
c.Assert(found[0].Version(), Equals, "v2")
c.Assert(found[0].IsActive(), Equals, true)
@@ -102,7 +108,18 @@
found = FindSnapsByNameAndVersion("linux", "v1", installed)
c.Assert(found, HasLen, 1)
c.Assert(found[0].Name(), Equals, "linux")
- c.Assert(found[0].Revision(), Equals, 20)
+ c.Assert(found[0].Revision(), Equals, snap.R(20))
c.Assert(found[0].Version(), Equals, "v1")
c.Assert(found[0].IsActive(), Equals, true)
}
+
+// SetNextBoot should do nothing on classic LP: #1580403
+func (s *kernelTestSuite) TestSetNextBootOnClassic(c *C) {
+ restore := release.MockOnClassic(true)
+ defer restore()
+
+ // Create a fake OS snap that we try to update
+ snapInfo := snaptest.MockSnap(c, "type: os", &snap.SideInfo{Revision: snap.R(42)})
+ err := SetNextBoot(snapInfo)
+ c.Assert(err, IsNil)
+}
diff -Nru snapd-2.0.5/snappy/overlord.go snapd-2.0.8/snappy/overlord.go
--- snapd-2.0.5/snappy/overlord.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/overlord.go 2016-06-08 05:58:01.000000000 +0000
@@ -27,14 +27,14 @@
"strings"
"time"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/systemd"
- "github.com/ubuntu-core/snappy/wrappers"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/systemd"
+ "github.com/snapcore/snapd/wrappers"
)
// Overlord is responsible for the overall system state.
@@ -61,10 +61,10 @@
return nil
}
-// CheckSnap ensures that the snap can be installed
-func CheckSnap(snapFilePath string, curInfo *snap.Info, flags InstallFlags, meter progress.Meter) error {
- allowGadget := (flags & AllowGadget) != 0
- allowUnauth := (flags & AllowUnauthenticated) != 0
+// checkSnap ensures that the snap can be installed
+func checkSnap(snapFilePath string, curInfo *snap.Info, flags LegacyInstallFlags, meter progress.Meter) error {
+ allowGadget := (flags & LegacyAllowGadget) != 0
+ allowUnauth := (flags & LegacyAllowUnauthenticated) != 0
// we do not Verify() the package here. This is done earlier in
// openSnapFile() to ensure that we do not mount/inspect
@@ -89,9 +89,9 @@
// SetupSnap does prepare and mount the snap for further processing
// It returns the installed path and an error
-func SetupSnap(snapFilePath string, sideInfo *snap.SideInfo, flags InstallFlags, meter progress.Meter) (snap.PlaceInfo, error) {
- inhibitHooks := (flags & InhibitHooks) != 0
- allowUnauth := (flags & AllowUnauthenticated) != 0
+func SetupSnap(snapFilePath string, sideInfo *snap.SideInfo, flags LegacyInstallFlags, meter progress.Meter) (snap.PlaceInfo, error) {
+ inhibitHooks := (flags & LegacyInhibitHooks) != 0
+ allowUnauth := (flags & LegacyAllowUnauthenticated) != 0
s, snapf, err := openSnapFile(snapFilePath, allowUnauth, sideInfo)
if err != nil {
@@ -109,13 +109,13 @@
}
// generate the mount unit for the squashfs
- if err := addSquashfsMount(s, inhibitHooks, meter); err != nil {
+ if err := addMountUnit(s, inhibitHooks, meter); err != nil {
return s, err
}
// FIXME: special handling is bad 'mkay
if s.Type == snap.TypeKernel {
- if err := extractKernelAssets(s, snapf, flags, meter); err != nil {
+ if err := extractKernelAssets(s, flags, meter); err != nil {
return s, fmt.Errorf("cannot install kernel: %s", err)
}
}
@@ -127,7 +127,7 @@
Notify(status string)
}
-func addSquashfsMount(s *snap.Info, inhibitHooks bool, inter interacter) error {
+func addMountUnit(s *snap.Info, noMount bool, inter interacter) error {
squashfsPath := stripGlobalRootDir(s.MountFile())
whereDir := stripGlobalRootDir(s.MountDir())
@@ -142,14 +142,14 @@
return err
}
- if !inhibitHooks {
+ if !noMount {
return sysd.Start(mountUnitName)
}
return nil
}
-func removeSquashfsMount(baseDir string, inter interacter) error {
+func removeMountUnit(baseDir string, inter interacter) error {
sysd := systemd.New(dirs.GlobalRootDir, inter)
unit := systemd.MountUnitPath(stripGlobalRootDir(baseDir), "mount")
if osutil.FileExists(unit) {
@@ -195,7 +195,7 @@
// and can only be used during install right now
}
-func CopyData(newSnap, oldSnap *snap.Info, flags InstallFlags, meter progress.Meter) error {
+func copyData(newSnap, oldSnap *snap.Info, flags LegacyInstallFlags, meter progress.Meter) error {
// deal with the old data or
// otherwise just create a empty data dir
@@ -212,16 +212,16 @@
return copySnapData(oldSnap, newSnap)
}
-func UndoCopyData(newInfo *snap.Info, flags InstallFlags, meter progress.Meter) {
+func undoCopyData(newInfo *snap.Info, flags LegacyInstallFlags, meter progress.Meter) {
// XXX we were copying data, assume InhibitHooks was false
- if err := RemoveSnapData(newInfo); err != nil {
+ if err := removeSnapData(newInfo); err != nil {
logger.Noticef("When cleaning up data for %s %s: %v", newInfo.Name(), newInfo.Version, err)
}
}
-func GenerateWrappers(s *snap.Info, inter interacter) error {
+func generateWrappers(s *snap.Info, inter interacter) error {
// add the CLI apps from the snap.yaml
if err := wrappers.AddSnapBinaries(s); err != nil {
return err
@@ -238,10 +238,9 @@
return nil
}
-// RemoveGeneratedWrappers removes the generated services, binaries, desktop
+// removeGeneratedWrappers removes the generated services, binaries, desktop
// wrappers
-func RemoveGeneratedWrappers(s *snap.Info, inter interacter) error {
-
+func removeGeneratedWrappers(s *snap.Info, inter interacter) error {
err1 := wrappers.RemoveSnapBinaries(s)
if err1 != nil {
logger.Noticef("Cannot remove binaries for %q: %v", s.Name(), err1)
@@ -260,8 +259,7 @@
return firstErr(err1, err2, err3)
}
-// XXX: would really like not to expose this but used in daemon tests atm
-func UpdateCurrentSymlink(info *snap.Info, inter interacter) error {
+func updateCurrentSymlink(info *snap.Info, inter interacter) error {
mountDir := info.MountDir()
currentActiveSymlink := filepath.Join(mountDir, "..", "current")
@@ -353,19 +351,19 @@
// security setup was done here!
- return LinkSnap(s.Info(), inter)
+ return linkSnap(s.Info(), inter)
}
-func LinkSnap(s *snap.Info, inter interacter) error {
- if err := GenerateWrappers(s, inter); err != nil {
+func linkSnap(s *snap.Info, inter interacter) error {
+ if err := generateWrappers(s, inter); err != nil {
return err
}
- return UpdateCurrentSymlink(s, inter)
+ return updateCurrentSymlink(s, inter)
}
-// UnlinkSnap deactivates the given active snap.
-func UnlinkSnap(info *snap.Info, inter interacter) error {
+// unlinkSnap deactivates the given active snap.
+func unlinkSnap(info *snap.Info, inter interacter) error {
mountDir := info.MountDir()
currentSymlink := filepath.Join(mountDir, "..", "current")
@@ -381,7 +379,7 @@
}
// remove generated services, binaries, security policy
- err1 := RemoveGeneratedWrappers(info, inter)
+ err1 := removeGeneratedWrappers(info, inter)
// removing security setup move here!
@@ -395,7 +393,7 @@
// Install installs the given snap file to the system.
//
// It returns the local snap file or an error
-func (o *Overlord) Install(snapFilePath string, flags InstallFlags, meter progress.Meter) (sp *snap.Info, err error) {
+func (o *Overlord) Install(snapFilePath string, flags LegacyInstallFlags, meter progress.Meter) (sp *snap.Info, err error) {
return o.InstallWithSideInfo(snapFilePath, nil, flags, meter)
}
@@ -403,7 +401,7 @@
// considering the provided side info.
//
// It returns the local snap file or an error
-func (o *Overlord) InstallWithSideInfo(snapFilePath string, sideInfo *snap.SideInfo, flags InstallFlags, meter progress.Meter) (sp *snap.Info, err error) {
+func (o *Overlord) InstallWithSideInfo(snapFilePath string, sideInfo *snap.SideInfo, flags LegacyInstallFlags, meter progress.Meter) (sp *snap.Info, err error) {
var oldInfo *snap.Info
if sideInfo != nil {
@@ -413,7 +411,7 @@
}
}
- if err := CheckSnap(snapFilePath, oldInfo, flags, meter); err != nil {
+ if err := checkSnap(snapFilePath, oldInfo, flags, meter); err != nil {
return nil, err
}
@@ -429,7 +427,7 @@
return nil, err
}
- allowUnauth := (flags & AllowUnauthenticated) != 0
+ allowUnauth := (flags & LegacyAllowUnauthenticated) != 0
newInfo, _, err := openSnapFile(snapFilePath, allowUnauth, sideInfo)
if err != nil {
return nil, err
@@ -438,7 +436,7 @@
// XXX: this is still done for now for this legacy Install to
// keep unit tests as they are working and as strawman
// behavior for current u-d-f
- if newInfo.Revision != 0 { // not sideloaded
+ if newInfo.Revision.Store() {
if err := SaveManifest(newInfo); err != nil {
return nil, err
}
@@ -448,10 +446,10 @@
// we need to stop any services and make the commands unavailable
// so that copying data and later activating the new revision
// can work
- err = UnlinkSnap(oldInfo, meter)
+ err = unlinkSnap(oldInfo, meter)
defer func() {
if err != nil {
- if err := LinkSnap(oldInfo, meter); err != nil {
+ if err := linkSnap(oldInfo, meter); err != nil {
logger.Noticef("When linking old revision: %v", newInfo.Name(), err)
}
}
@@ -462,10 +460,10 @@
}
// deal with the data
- err = CopyData(newInfo, oldInfo, flags, meter)
+ err = copyData(newInfo, oldInfo, flags, meter)
defer func() {
if err != nil {
- UndoCopyData(newInfo, flags, meter)
+ undoCopyData(newInfo, flags, meter)
}
}()
if err != nil {
@@ -474,15 +472,15 @@
// and finally make active
- if (flags & InhibitHooks) != 0 {
+ if (flags & LegacyInhibitHooks) != 0 {
// XXX: kill InhibitHooks flag but used by u-d-f atm
return newInfo, nil
}
- err = LinkSnap(newInfo, meter)
+ err = linkSnap(newInfo, meter)
defer func() {
if err != nil {
- if err := UnlinkSnap(newInfo, meter); err != nil {
+ if err := unlinkSnap(newInfo, meter); err != nil {
logger.Noticef("When unlinking failed new snap revision: %v", newInfo.Name(), err)
}
}
@@ -495,29 +493,18 @@
}
// CanInstall checks whether the Snap passes a series of tests required for installation
-func canInstall(s *snap.Info, snapf snap.File, curInfo *snap.Info, allowGadget bool, inter interacter) error {
+func canInstall(s *snap.Info, snapf snap.Container, curInfo *snap.Info, allowGadget bool, inter interacter) error {
// verify we have a valid architecture
if !arch.IsSupportedArchitecture(s.Architectures) {
return &ErrArchitectureNotSupported{s.Architectures}
}
- if s.Type == snap.TypeGadget {
- if !allowGadget {
- if currentGadget, err := getGadget(); err == nil {
- if currentGadget.Name() != s.Name() {
- return ErrGadgetPackageInstall
- }
- } else {
- // there should always be a gadget package now
- return ErrGadgetPackageInstall
- }
- }
- }
+ // assume allowGadget, this is only used by u-d-f now
return nil
}
-func CanRemove(s *snap.Info, active bool) bool {
+func canRemove(s *snap.Info, active bool) bool {
// Gadget snaps should not be removed as they are a key
// building block for Gadgets. Prunning non active ones
// is acceptible.
@@ -549,7 +536,7 @@
snapPath := s.MountFile()
// this also ensures that the mount unit stops
- if err := removeSquashfsMount(mountDir, meter); err != nil {
+ if err := removeMountUnit(mountDir, meter); err != nil {
return err
}
@@ -579,11 +566,11 @@
//
// It returns an error on failure
func (o *Overlord) Uninstall(s *Snap, meter progress.Meter) error {
- if !CanRemove(s.Info(), s.IsActive()) {
+ if !canRemove(s.Info(), s.IsActive()) {
return ErrPackageNotRemovable
}
- if err := UnlinkSnap(s.Info(), meter); err != nil && err != ErrSnapNotActive {
+ if err := unlinkSnap(s.Info(), meter); err != nil && err != ErrSnapNotActive {
return err
}
@@ -591,7 +578,7 @@
return err
}
- return RemoveSnapData(s.Info())
+ return removeSnapData(s.Info())
}
// SetActive sets the active state of the given snap
@@ -601,14 +588,14 @@
if active {
// deactivate current first
if current := ActiveSnapByName(s.Name()); current != nil {
- if err := UnlinkSnap(current.Info(), meter); err != nil {
+ if err := unlinkSnap(current.Info(), meter); err != nil {
return err
}
}
return ActivateSnap(s, meter)
}
- return UnlinkSnap(s.Info(), meter)
+ return unlinkSnap(s.Info(), meter)
}
// Installed returns the installed snaps from this repository
diff -Nru snapd-2.0.5/snappy/overlord_test.go snapd-2.0.8/snappy/overlord_test.go
--- snapd-2.0.5/snappy/overlord_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/overlord_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,10 +28,10 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/systemd"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/systemd"
)
var helloAppYaml = `name: hello-snap
@@ -61,19 +61,19 @@
func (s *SnapTestSuite) TestLocalSnapInstall(c *C) string {
snapPath := makeTestSnapPackage(c, "")
- // revision will be 0
+ // XXX Broken test: revision will be unset
snap, err := (&Overlord{}).Install(snapPath, 0, nil)
c.Assert(err, IsNil)
c.Check(snap.Name(), Equals, "foo")
- baseDir := filepath.Join(dirs.SnapSnapsDir, fooComposedName, "0")
+ baseDir := filepath.Join(dirs.SnapSnapsDir, fooComposedName, "unset")
c.Assert(osutil.FileExists(baseDir), Equals, true)
snapEntries := listDir(c, filepath.Join(dirs.SnapSnapsDir, fooComposedName))
- c.Check(snapEntries, DeepEquals, []string{"0", "current"})
+ c.Check(snapEntries, DeepEquals, []string{"current", "unset"})
snapDataEntries := listDir(c, filepath.Join(dirs.SnapDataDir, fooComposedName))
- c.Check(snapDataEntries, DeepEquals, []string{"0", "common", "current"})
+ c.Check(snapDataEntries, DeepEquals, []string{"common", "current", "unset"})
return snapPath
}
@@ -83,13 +83,13 @@
si := &snap.SideInfo{
OfficialName: "foo",
- Revision: 40,
+ Revision: snap.R(40),
}
- snap, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, 0, nil)
+ sn, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, 0, nil)
c.Assert(err, IsNil)
- c.Check(snap.Name(), Equals, "foo")
- c.Check(snap.Revision, Equals, 40)
+ c.Check(sn.Name(), Equals, "foo")
+ c.Check(sn.Revision, Equals, snap.R(40))
baseDir := filepath.Join(dirs.SnapSnapsDir, fooComposedName, "40")
c.Assert(osutil.FileExists(baseDir), Equals, true)
@@ -106,13 +106,13 @@
si := &snap.SideInfo{
OfficialName: "bar",
- Revision: 55,
+ Revision: snap.R(55),
}
- snap, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, 0, nil)
+ sn, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, 0, nil)
c.Assert(err, IsNil)
- c.Check(snap.Name(), Equals, "bar")
- c.Check(snap.Revision, Equals, 55)
+ c.Check(sn.Name(), Equals, "bar")
+ c.Check(sn.Revision, Equals, snap.R(55))
baseDir := filepath.Join(dirs.SnapSnapsDir, "bar", "55")
c.Assert(osutil.FileExists(baseDir), Equals, true)
@@ -171,71 +171,25 @@
version: 1.0
type: gadget
`)
- // revision will be 0
- _, err := (&Overlord{}).Install(snapPath, AllowGadget, nil)
- c.Assert(err, IsNil)
-
- contentFile := filepath.Join(dirs.SnapSnapsDir, "foo", "0", "bin", "foo")
- _, err = os.Stat(contentFile)
- c.Assert(err, IsNil)
-}
-
-func (s *SnapTestSuite) TestLocalGadgetSnapInstallVariants(c *C) {
- snapPath := makeTestSnapPackage(c, `name: foo
-version: 1.0
-type: gadget
-`)
-
- foo10 := &snap.SideInfo{
- OfficialName: "foo",
- Developer: testDeveloper,
- Revision: 100,
- Channel: "remote-channel",
- }
- _, err := (&Overlord{}).InstallWithSideInfo(snapPath, foo10, AllowGadget, nil)
+ // XXX Broken test: revision will be unset
+ _, err := (&Overlord{}).Install(snapPath, LegacyAllowGadget, nil)
c.Assert(err, IsNil)
- contentFile := filepath.Join(dirs.SnapSnapsDir, "foo", "100", "bin", "foo")
+ contentFile := filepath.Join(dirs.SnapSnapsDir, "foo", "unset", "bin", "foo")
_, err = os.Stat(contentFile)
c.Assert(err, IsNil)
-
- // a package update
- snapPath = makeTestSnapPackage(c, `name: foo
-version: 2.0
-type: gadget
-`)
- foo20 := &snap.SideInfo{
- OfficialName: "foo",
- Developer: testDeveloper,
- Revision: 200,
- Channel: "remote-channel",
- }
- _, err = (&Overlord{}).InstallWithSideInfo(snapPath, foo20, 0, nil)
- c.Check(err, IsNil)
-
- // a package name fork, IOW, a different Gadget package.
- snapPath = makeTestSnapPackage(c, `name: foo-fork
-version: 2.0
-type: gadget
-`)
- _, err = (&Overlord{}).Install(snapPath, 0, nil)
- c.Check(err, Equals, ErrGadgetPackageInstall)
-
- // this will cause chaos, but let's test if it works
- _, err = (&Overlord{}).Install(snapPath, AllowGadget, nil)
- c.Check(err, IsNil)
}
// sideinfos
var (
fooSI10 = &snap.SideInfo{
OfficialName: "foo",
- Revision: 10,
+ Revision: snap.R(10),
}
fooSI20 = &snap.SideInfo{
OfficialName: "foo",
- Revision: 20,
+ Revision: snap.R(20),
}
)
@@ -243,11 +197,11 @@
snapYamlContent := `name: foo
`
snapPath := makeTestSnapPackage(c, snapYamlContent+"version: 1.0")
- _, err := (&Overlord{}).InstallWithSideInfo(snapPath, fooSI10, AllowUnauthenticated, nil)
+ _, err := (&Overlord{}).InstallWithSideInfo(snapPath, fooSI10, LegacyAllowUnauthenticated, nil)
c.Assert(err, IsNil)
snapPath = makeTestSnapPackage(c, snapYamlContent+"version: 2.0")
- _, err = (&Overlord{}).InstallWithSideInfo(snapPath, fooSI20, AllowUnauthenticated, nil)
+ _, err = (&Overlord{}).InstallWithSideInfo(snapPath, fooSI20, LegacyAllowUnauthenticated, nil)
c.Assert(err, IsNil)
// ensure v2 is active
@@ -260,7 +214,7 @@
c.Assert(snaps[1].IsActive(), Equals, true)
// deactivate v2
- err = UnlinkSnap(snaps[1].Info(), nil)
+ err = unlinkSnap(snaps[1].Info(), nil)
// set v1 active
err = ActivateSnap(snaps[0], nil)
snaps, err = (&Overlord{}).Installed()
@@ -272,94 +226,6 @@
}
-func (s *SnapTestSuite) TestCopyData(c *C) {
- dirs.SnapDataHomeGlob = filepath.Join(s.tempdir, "home", "*", "snap")
- homeDir := filepath.Join(s.tempdir, "home", "user1", "snap")
- appDir := "foo"
- homeData := filepath.Join(homeDir, appDir, "10")
- err := os.MkdirAll(homeData, 0755)
- c.Assert(err, IsNil)
- homeCommonData := filepath.Join(homeDir, appDir, "common")
- err = os.MkdirAll(homeCommonData, 0755)
- c.Assert(err, IsNil)
-
- snapYamlContent := `name: foo
-`
- canaryData := []byte("ni ni ni")
-
- snapPath := makeTestSnapPackage(c, snapYamlContent+"version: 1.0")
- _, err = (&Overlord{}).InstallWithSideInfo(snapPath, fooSI10, AllowUnauthenticated, nil)
- c.Assert(err, IsNil)
- canaryDataFile := filepath.Join(dirs.SnapDataDir, appDir, "10", "canary.txt")
- err = ioutil.WriteFile(canaryDataFile, canaryData, 0644)
- c.Assert(err, IsNil)
- canaryDataFile = filepath.Join(dirs.SnapDataDir, appDir, "common", "canary.common")
- err = ioutil.WriteFile(canaryDataFile, canaryData, 0644)
- c.Assert(err, IsNil)
- err = ioutil.WriteFile(filepath.Join(homeData, "canary.home"), canaryData, 0644)
- c.Assert(err, IsNil)
- err = ioutil.WriteFile(filepath.Join(homeCommonData, "canary.common_home"), canaryData, 0644)
- c.Assert(err, IsNil)
-
- snapPath = makeTestSnapPackage(c, snapYamlContent+"version: 2.0")
- _, err = (&Overlord{}).InstallWithSideInfo(snapPath, fooSI20, AllowUnauthenticated, nil)
- c.Assert(err, IsNil)
- newCanaryDataFile := filepath.Join(dirs.SnapDataDir, appDir, "20", "canary.txt")
- content, err := ioutil.ReadFile(newCanaryDataFile)
- c.Assert(err, IsNil)
- c.Assert(content, DeepEquals, canaryData)
-
- // ensure common data file is still there (even though it didn't get copied)
- newCanaryDataFile = filepath.Join(dirs.SnapDataDir, appDir, "common", "canary.common")
- content, err = ioutil.ReadFile(newCanaryDataFile)
- c.Assert(err, IsNil)
- c.Assert(content, DeepEquals, canaryData)
-
- newCanaryDataFile = filepath.Join(homeDir, appDir, "20", "canary.home")
- content, err = ioutil.ReadFile(newCanaryDataFile)
- c.Assert(err, IsNil)
- c.Assert(content, DeepEquals, canaryData)
-
- // ensure home common data file is still there (even though it didn't get copied)
- newCanaryDataFile = filepath.Join(homeDir, appDir, "common", "canary.common_home")
- content, err = ioutil.ReadFile(newCanaryDataFile)
- c.Assert(err, IsNil)
- c.Assert(content, DeepEquals, canaryData)
-}
-
-// ensure that even with no home dir there is no error and the
-// system data gets copied
-func (s *SnapTestSuite) TestCopyDataNoUserHomes(c *C) {
- // this home dir path does not exist
- oldSnapDataHomeGlob := dirs.SnapDataHomeGlob
- defer func() { dirs.SnapDataHomeGlob = oldSnapDataHomeGlob }()
- dirs.SnapDataHomeGlob = filepath.Join(s.tempdir, "no-such-home", "*", "snap")
-
- snapYamlContent := `name: foo
-`
- snapPath := makeTestSnapPackage(c, snapYamlContent+"version: 1.0")
- snap, err := (&Overlord{}).InstallWithSideInfo(snapPath, fooSI10, AllowUnauthenticated, nil)
- c.Assert(err, IsNil)
- canaryDataFile := filepath.Join(snap.DataDir(), "canary.txt")
- err = ioutil.WriteFile(canaryDataFile, []byte(""), 0644)
- c.Assert(err, IsNil)
- canaryDataFile = filepath.Join(snap.CommonDataDir(), "canary.common")
- err = ioutil.WriteFile(canaryDataFile, []byte(""), 0644)
- c.Assert(err, IsNil)
-
- snapPath = makeTestSnapPackage(c, snapYamlContent+"version: 2.0")
- snap2, err := (&Overlord{}).InstallWithSideInfo(snapPath, fooSI20, AllowUnauthenticated, nil)
- c.Assert(err, IsNil)
- _, err = os.Stat(filepath.Join(snap2.DataDir(), "canary.txt"))
- c.Assert(err, IsNil)
- _, err = os.Stat(filepath.Join(snap2.CommonDataDir(), "canary.common"))
- c.Assert(err, IsNil)
-
- // sanity atm
- c.Check(snap.DataDir(), Not(Equals), snap2.DataDir())
- c.Check(snap.CommonDataDir(), Equals, snap2.CommonDataDir())
-}
-
func (s *SnapTestSuite) TestSnappyHandleBinariesOnUpgrade(c *C) {
snapYamlContent := `name: foo
apps:
@@ -367,7 +233,7 @@
command: bin/bar
`
snapPath := makeTestSnapPackage(c, snapYamlContent+"version: 1.0")
- _, err := (&Overlord{}).InstallWithSideInfo(snapPath, fooSI10, AllowUnauthenticated, nil)
+ _, err := (&Overlord{}).InstallWithSideInfo(snapPath, fooSI10, LegacyAllowUnauthenticated, nil)
c.Assert(err, IsNil)
// ensure that the binary wrapper file got generated with the right
@@ -380,7 +246,7 @@
// and that it gets updated on upgrade
snapPath = makeTestSnapPackage(c, snapYamlContent+"version: 2.0")
- _, err = (&Overlord{}).InstallWithSideInfo(snapPath, fooSI20, AllowUnauthenticated, nil)
+ _, err = (&Overlord{}).InstallWithSideInfo(snapPath, fooSI20, LegacyAllowUnauthenticated, nil)
c.Assert(err, IsNil)
newSnapBin := filepath.Join(dirs.SnapSnapsDir[len(dirs.GlobalRootDir):], "foo", "20", "bin", "bar")
content, err = ioutil.ReadFile(binaryWrapper)
@@ -397,12 +263,12 @@
`
si := &snap.SideInfo{
OfficialName: "foo",
- Revision: 32,
+ Revision: snap.R(32),
}
snapPath := makeTestSnapPackage(c, snapYamlContent+"version: 1.0")
- // revision will be 0
- _, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, AllowUnauthenticated, nil)
+ // XXX Broken test: revision will be unset
+ _, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, LegacyAllowUnauthenticated, nil)
c.Assert(err, IsNil)
servicesFile := filepath.Join(dirs.SnapServicesDir, "snap.foo.service.service")
@@ -439,7 +305,7 @@
daemon: forking
`
snapPath := makeTestSnapPackage(c, snapYamlContent+"version: 1.0")
- _, err := (&Overlord{}).Install(snapPath, InhibitHooks, nil)
+ _, err := (&Overlord{}).Install(snapPath, LegacyInhibitHooks, nil)
c.Assert(err, IsNil)
c.Assert(allSystemctl, HasLen, 0)
@@ -453,8 +319,8 @@
command: bin/bar
`
snapPath := makeTestSnapPackage(c, snapYamlContent+"version: 1.0")
- // revision will be 0
- _, err := (&Overlord{}).Install(snapPath, AllowUnauthenticated, nil)
+ // XXX Broken test: revision will be unset
+ _, err := (&Overlord{}).Install(snapPath, LegacyAllowUnauthenticated, nil)
c.Assert(err, IsNil)
// ensure that the binary wrapper file go generated with the right
@@ -463,7 +329,7 @@
c.Assert(osutil.FileExists(binaryWrapper), Equals, true)
// and that it gets removed on remove
- snapDir := filepath.Join(dirs.SnapSnapsDir, "foo", "0")
+ snapDir := filepath.Join(dirs.SnapSnapsDir, "foo", "unset")
yamlPath := filepath.Join(snapDir, "meta", "snap.yaml")
snap, err := NewInstalledSnap(yamlPath)
c.Assert(err, IsNil)
@@ -484,7 +350,7 @@
si := &snap.SideInfo{
OfficialName: "bar",
- Revision: 55,
+ Revision: snap.R(55),
}
_, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, 0, &MockProgressMeter{})
@@ -505,7 +371,7 @@
`
snapPath := makeTestSnapPackage(c, snapYamlContent+"version: 1.0")
// Use InstallWithSideInfo, this is just a cheap way to call openSnapFile
- snapInfo, err := (&Overlord{}).InstallWithSideInfo(snapPath, fooSI10, AllowUnauthenticated, nil)
+ snapInfo, err := (&Overlord{}).InstallWithSideInfo(snapPath, fooSI10, LegacyAllowUnauthenticated, nil)
c.Assert(err, IsNil)
// Ensure that side info is correctly stored
diff -Nru snapd-2.0.5/snappy/remove.go snapd-2.0.8/snappy/remove.go
--- snapd-2.0.5/snappy/remove.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/remove.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,29 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-
-/*
- * Copyright (C) 2014-2015 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package snappy
-
-// RemoveFlags can be used to pass additional flags to the snap removal request
-type RemoveFlags uint
-
-const (
- // DoRemoveGC will ensure that garbage collection is done, unless a
- // version is specified.
- DoRemoveGC RemoveFlags = 1 << iota
-)
diff -Nru snapd-2.0.5/snappy/remove_test.go snapd-2.0.8/snappy/remove_test.go
--- snapd-2.0.5/snappy/remove_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/remove_test.go 1970-01-01 00:00:00.000000000 +0000
@@ -1,45 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-
-/*
- * Copyright (C) 2014-2015 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package snappy
-
-import (
- . "gopkg.in/check.v1"
-
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
-)
-
-func (s *SnapTestSuite) TestUnlinkSnapActiveVsNotActive(c *C) {
- foo1, foo2 := makeTwoTestSnaps(c, snap.TypeApp)
-
- err := UnlinkSnap(foo2, &progress.NullProgress{})
- c.Assert(err, IsNil)
-
- err = UnlinkSnap(foo1, &progress.NullProgress{})
- c.Assert(err, Equals, ErrSnapNotActive)
-}
-
-func (s *SnapTestSuite) TestCanRemoveGadget(c *C) {
- foo1, foo2 := makeTwoTestSnaps(c, snap.TypeGadget)
-
- c.Check(CanRemove(foo2, true), Equals, false)
-
- c.Check(CanRemove(foo1, false), Equals, true)
-}
diff -Nru snapd-2.0.5/snappy/snapdata.go snapd-2.0.8/snappy/snapdata.go
--- snapd-2.0.5/snappy/snapdata.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/snapdata.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,12 +24,12 @@
"os/exec"
"path/filepath"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
)
// RemoveSnapData removes the data for the given version of the given snap
-func RemoveSnapData(snap *snap.Info) error {
+func removeSnapData(snap *snap.Info) error {
dirs, err := snapDataDirs(snap)
if err != nil {
return err
@@ -39,7 +39,7 @@
}
// RemoveSnapCommonData removes the data common between versions of the given snap
-func RemoveSnapCommonData(snap *snap.Info) error {
+func removeSnapCommonData(snap *snap.Info) error {
dirs, err := snapCommonDataDirs(snap)
if err != nil {
return err
diff -Nru snapd-2.0.5/snappy/snap_file.go snapd-2.0.8/snappy/snap_file.go
--- snapd-2.0.5/snappy/snap_file.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/snap_file.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,12 +20,12 @@
package snappy
import (
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
// openSnapFile opens a snap blob returning both a snap.Info completed
-// with sideInfo (if not nil) and a corresponding snap.File.
-func openSnapFile(snapPath string, unsignedOk bool, sideInfo *snap.SideInfo) (*snap.Info, snap.File, error) {
+// with sideInfo (if not nil) and a corresponding snap.Container.
+func openSnapFile(snapPath string, unsignedOk bool, sideInfo *snap.SideInfo) (*snap.Info, snap.Container, error) {
// TODO: what precautions to take if unsignedOk == false ?
snapf, err := snap.Open(snapPath)
diff -Nru snapd-2.0.5/snappy/snap_local.go snapd-2.0.8/snappy/snap_local.go
--- snapd-2.0.5/snappy/snap_local.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/snap_local.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,12 +24,11 @@
"io/ioutil"
"os"
"path/filepath"
- "strconv"
"gopkg.in/yaml.v2"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
)
// Snap represents a generic snap type
@@ -46,10 +45,9 @@
// XXX: hack the name and revision out of the path for now
// snapstate primitives shouldn't need this
name := filepath.Base(filepath.Dir(mountDir))
- revnoStr := filepath.Base(mountDir)
- revno, err := strconv.Atoi(revnoStr)
+ revno, err := snap.ParseRevision(filepath.Base(mountDir))
if err != nil {
- return nil, fmt.Errorf("broken snap directory path: %q", mountDir)
+ return nil, fmt.Errorf("broken snap directory path, bad revision: %q", mountDir)
}
s := &Snap{}
@@ -77,7 +75,7 @@
s.info = info
- if revno != 0 {
+ if revno.Store() {
mfPath := manifestPath(name, revno)
if osutil.FileExists(mfPath) {
content, err := ioutil.ReadFile(mfPath)
@@ -120,7 +118,7 @@
}
// Revision returns the revision
-func (s *Snap) Revision() int {
+func (s *Snap) Revision() snap.Revision {
return s.info.Revision
}
diff -Nru snapd-2.0.5/snappy/snapp_snapfs_test.go snapd-2.0.8/snappy/snapp_snapfs_test.go
--- snapd-2.0.5/snappy/snapp_snapfs_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/snapp_snapfs_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,13 +24,14 @@
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/partition"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/squashfs"
- "github.com/ubuntu-core/snappy/systemd"
- "github.com/ubuntu-core/snappy/testutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/partition"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/squashfs"
+ "github.com/snapcore/snapd/systemd"
+ "github.com/snapcore/snapd/testutil"
. "gopkg.in/check.v1"
)
@@ -119,20 +120,20 @@
func (s *SquashfsTestSuite) TestOpenSnapFilebSideInfo(c *C) {
snapPkg := makeTestSnapPackage(c, packageHello)
- si := snap.SideInfo{OfficialName: "blessed", Revision: 42}
+ si := snap.SideInfo{OfficialName: "blessed", Revision: snap.R(42)}
info, _, err := openSnapFile(snapPkg, true, &si)
c.Assert(err, IsNil)
// check side info
c.Check(info.Name(), Equals, "blessed")
- c.Check(info.Revision, Equals, 42)
+ c.Check(info.Revision, Equals, snap.R(42))
}
func (s *SquashfsTestSuite) TestInstallViaSquashfsWorks(c *C) {
snapPkg := makeTestSnapPackage(c, packageHello)
si := &snap.SideInfo{
OfficialName: "hello-snap",
- Revision: 16,
+ Revision: snap.R(16),
}
_, err := (&Overlord{}).InstallWithSideInfo(snapPkg, si, 0, &MockProgressMeter{})
c.Assert(err, IsNil)
@@ -148,24 +149,24 @@
c.Assert(string(content), Matches, "(?ms).*^What=/var/lib/snapd/snaps/hello-snap_16.snap")
}
-func (s *SquashfsTestSuite) TestAddSquashfsMount(c *C) {
+func (s *SquashfsTestSuite) TestAddMountUnit(c *C) {
info := &snap.Info{
SideInfo: snap.SideInfo{
OfficialName: "foo",
- Revision: 13,
+ Revision: snap.R(13),
},
Version: "1.1",
Architectures: []string{"all"},
}
inter := &MockProgressMeter{}
- err := addSquashfsMount(info, true, inter)
+ err := addMountUnit(info, true, inter)
c.Assert(err, IsNil)
// ensure correct mount unit
mount, err := ioutil.ReadFile(filepath.Join(dirs.SnapServicesDir, "snap-foo-13.mount"))
c.Assert(err, IsNil)
c.Assert(string(mount), Equals, `[Unit]
-Description=Squashfs mount unit for foo
+Description=Mount unit for foo
[Mount]
What=/var/lib/snapd/snaps/foo_13.snap
@@ -177,17 +178,17 @@
}
-func (s *SquashfsTestSuite) TestRemoveSquashfsMountUnit(c *C) {
+func (s *SquashfsTestSuite) TestRemoveMountUnit(c *C) {
info := &snap.Info{
SideInfo: snap.SideInfo{
OfficialName: "foo",
- Revision: 13,
+ Revision: snap.R(13),
},
Version: "1.1",
Architectures: []string{"all"},
}
inter := &MockProgressMeter{}
- err := addSquashfsMount(info, true, inter)
+ err := addMountUnit(info, true, inter)
c.Assert(err, IsNil)
// ensure we have the files
@@ -195,7 +196,7 @@
c.Assert(osutil.FileExists(p), Equals, true)
// now call remove and ensure they are gone
- err = removeSquashfsMount(info.MountDir(), inter)
+ err = removeMountUnit(info.MountDir(), inter)
c.Assert(err, IsNil)
p = filepath.Join(dirs.SnapServicesDir, "snaps-foo-13.mount")
c.Assert(osutil.FileExists(p), Equals, false)
@@ -205,7 +206,7 @@
snapPath := makeTestSnapPackage(c, packageHello)
si := &snap.SideInfo{
OfficialName: "hello-snap",
- Revision: 16,
+ Revision: snap.R(16),
}
snap, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, 0, &MockProgressMeter{})
c.Assert(err, IsNil)
@@ -230,10 +231,13 @@
`
func (s *SquashfsTestSuite) TestInstallOsSnapUpdatesBootloader(c *C) {
+ restore := release.MockOnClassic(false)
+ defer restore()
+
snapPkg := makeTestSnapPackage(c, packageOS)
si := &snap.SideInfo{
OfficialName: "ubuntu-core",
- Revision: 160,
+ Revision: snap.R(160),
}
_, err := (&Overlord{}).InstallWithSideInfo(snapPkg, si, 0, &MockProgressMeter{})
c.Assert(err, IsNil)
@@ -252,6 +256,9 @@
`
func (s *SquashfsTestSuite) TestInstallKernelSnapUpdatesBootloader(c *C) {
+ restore := release.MockOnClassic(false)
+ defer restore()
+
files := [][]string{
{"kernel.img", "I'm a kernel"},
{"initrd.img", "...and I'm an initrd"},
@@ -260,7 +267,7 @@
snapPkg := makeTestSnapPackageWithFiles(c, packageKernel, files)
si := &snap.SideInfo{
OfficialName: "ubuntu-kernel",
- Revision: 40,
+ Revision: snap.R(40),
}
_, err := (&Overlord{}).InstallWithSideInfo(snapPkg, si, 0, &MockProgressMeter{})
c.Assert(err, IsNil)
@@ -283,7 +290,7 @@
snapPkg := makeTestSnapPackageWithFiles(c, packageKernel, files)
si := &snap.SideInfo{
OfficialName: "ubuntu-kernel",
- Revision: 42,
+ Revision: snap.R(42),
}
_, err := (&Overlord{}).InstallWithSideInfo(snapPkg, si, 0, &MockProgressMeter{})
c.Assert(err, IsNil)
@@ -311,7 +318,7 @@
snapPkg := makeTestSnapPackageWithFiles(c, packageKernel, files)
si := &snap.SideInfo{
OfficialName: "ubuntu-kernel",
- Revision: 42,
+ Revision: snap.R(42),
}
snap, err := (&Overlord{}).InstallWithSideInfo(snapPkg, si, 0, &MockProgressMeter{})
c.Assert(err, IsNil)
@@ -341,10 +348,10 @@
func (s *SquashfsTestSuite) TestInstallKernelSnapUnpacksKernelErrors(c *C) {
snapPkg := makeTestSnapPackage(c, packageHello)
- snap, snapf, err := openSnapFile(snapPkg, true, nil)
+ snap, _, err := openSnapFile(snapPkg, true, nil)
c.Assert(err, IsNil)
- err = extractKernelAssets(snap, snapf, 0, nil)
+ err = extractKernelAssets(snap, 0, nil)
c.Assert(err, ErrorMatches, `cannot extract kernel assets from snap type "app"`)
}
diff -Nru snapd-2.0.5/snappy/snapp_test.go snapd-2.0.8/snappy/snapp_test.go
--- snapd-2.0.5/snappy/snapp_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/snapp_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,20 +22,19 @@
import (
"fmt"
"io"
- "io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/policy"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snapenv"
- "github.com/ubuntu-core/snappy/store"
- "github.com/ubuntu-core/snappy/systemd"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/policy"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snapenv"
+ "github.com/snapcore/snapd/store"
+ "github.com/snapcore/snapd/systemd"
. "gopkg.in/check.v1"
)
@@ -100,17 +99,17 @@
snapYaml, err := makeInstalledMockSnap("", 15)
c.Assert(err, IsNil)
- snap, err := NewInstalledSnap(snapYaml)
+ sn, err := NewInstalledSnap(snapYaml)
c.Assert(err, IsNil)
- c.Assert(snap, NotNil)
- c.Check(snap.Name(), Equals, "hello-snap")
- c.Check(snap.Version(), Equals, "1.10")
- c.Check(snap.IsActive(), Equals, false)
- c.Check(snap.Info().Summary(), Equals, "hello in summary")
- c.Check(snap.Info().Description(), Equals, "Hello...")
- c.Check(snap.Info().Revision, Equals, 15)
+ c.Assert(sn, NotNil)
+ c.Check(sn.Name(), Equals, "hello-snap")
+ c.Check(sn.Version(), Equals, "1.10")
+ c.Check(sn.IsActive(), Equals, false)
+ c.Check(sn.Info().Summary(), Equals, "hello in summary")
+ c.Check(sn.Info().Description(), Equals, "Hello...")
+ c.Check(sn.Info().Revision, Equals, snap.R(15))
- mountDir := snap.Info().MountDir()
+ mountDir := sn.Info().MountDir()
_, err = os.Stat(mountDir)
c.Assert(err, IsNil)
@@ -152,80 +151,6 @@
funkyAppName = "8nzc1x4iim2xj1g2ul64"
)
-/* acquired via:
-curl -s --data-binary '{"name":["8nzc1x4iim2xj1g2ul64.chipaca"]}' -H 'content-type: application/json' https://search.apps.ubuntu.com/api/v1/click-metadata
-*/
-const MockUpdatesJSON = `[
- {
- "status": "Published",
- "name": "8nzc1x4iim2xj1g2ul64.chipaca",
- "package_name": "8nzc1x4iim2xj1g2ul64",
- "origin": "chipaca",
- "changelog": "",
- "icon_url": "https://myapps.developer.ubuntu.com/site_media/appmedia/2015/04/hello.svg_Dlrd3L4.png",
- "title": "Returns for store credit only.",
- "binary_filesize": 65375,
- "anon_download_url": "https://public.apps.ubuntu.com/anon/download/chipaca/8nzc1x4iim2xj1g2ul64.chipaca/8nzc1x4iim2xj1g2ul64.chipaca_42_all.snap",
- "allow_unauthenticated": true,
- "revision": 3,
- "version": "42",
- "download_url": "https://public.apps.ubuntu.com/download/chipaca/8nzc1x4iim2xj1g2ul64.chipaca/8nzc1x4iim2xj1g2ul64.chipaca_42_all.snap",
- "download_sha512": "5364253e4a988f4f5c04380086d542f410455b97d48cc6c69ca2a5877d8aef2a6b2b2f83ec4f688cae61ebc8a6bf2cdbd4dbd8f743f0522fc76540429b79df42"
- }
-]`
-
-func mockActiveSnapIterByType(mockSnaps []string) {
- ActiveSnapIterByType = func(f func(*snap.Info) string, snapTs ...snap.Type) (res []string, err error) {
- return mockSnaps, nil
- }
-}
-
-func (s *SnapTestSuite) TestUbuntuStoreRepositoryUpdates(c *C) {
- mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- jsonReq, err := ioutil.ReadAll(r.Body)
- c.Assert(err, IsNil)
- c.Assert(string(jsonReq), Equals, `{"name":["`+funkyAppName+`"]}`)
- io.WriteString(w, MockUpdatesJSON)
- }))
-
- c.Assert(mockServer, NotNil)
- defer mockServer.Close()
-
- var err error
- s.storeCfg.BulkURI, err = url.Parse(mockServer.URL + "/updates/")
- c.Assert(err, IsNil)
- repo := store.NewUbuntuStoreSnapRepository(s.storeCfg, "")
- c.Assert(repo, NotNil)
-
- // override the real ActiveSnapIterByType to return our
- // mock data
- mockActiveSnapIterByType([]string{funkyAppName})
-
- // the actual test
- results, err := snapUpdates(repo)
- c.Assert(err, IsNil)
- c.Assert(results, HasLen, 1)
- c.Assert(results[0].Name(), Equals, funkyAppName)
- c.Assert(results[0].Revision, Equals, 3)
- c.Assert(results[0].Version, Equals, "42")
-}
-
-func (s *SnapTestSuite) TestUbuntuStoreRepositoryUpdatesNoSnaps(c *C) {
-
- var err error
- s.storeCfg.SearchURI, err = url.Parse("https://some-uri")
- c.Assert(err, IsNil)
- repo := store.NewUbuntuStoreSnapRepository(s.storeCfg, "")
- c.Assert(repo, NotNil)
-
- mockActiveSnapIterByType([]string{})
-
- // the actual test
- results, err := snapUpdates(repo)
- c.Assert(err, IsNil)
- c.Assert(results, HasLen, 0)
-}
-
func (s *SnapTestSuite) TestMakeConfigEnv(c *C) {
yamlFile, err := makeInstalledMockSnap("", 11)
c.Assert(err, IsNil)
@@ -266,7 +191,7 @@
r := &snap.Info{}
r.OfficialName = "foo"
- r.Revision = 42
+ r.Revision = snap.R(42)
r.Developer = "bar"
r.EditedDescription = "this is a description"
r.Version = "1.0"
@@ -287,7 +212,7 @@
c.Assert(err, IsNil)
c.Assert(installed, HasLen, 1)
- c.Check(installed[0].Info().Revision, Equals, 42)
+ c.Check(installed[0].Info().Revision, Equals, snap.R(42))
c.Check(installed[0].Developer(), Equals, "bar")
c.Check(installed[0].Info().Description(), Equals, "this is a description")
diff -Nru snapd-2.0.5/snappy/sort.go snapd-2.0.8/snappy/sort.go
--- snapd-2.0.5/snappy/sort.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/sort.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
"strconv"
"strings"
- "github.com/ubuntu-core/snappy/logger"
+ "github.com/snapcore/snapd/logger"
)
const (
diff -Nru snapd-2.0.5/snappy/sort_test.go snapd-2.0.8/snappy/sort_test.go
--- snapd-2.0.5/snappy/sort_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/sort_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,7 +24,7 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
type SortTestSuite struct {
diff -Nru snapd-2.0.5/snappy/undo_test.go snapd-2.0.8/snappy/undo_test.go
--- snapd-2.0.5/snappy/undo_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/undo_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,18 +20,17 @@
package snappy
import (
- "io/ioutil"
"os"
"path/filepath"
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/partition"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/systemd"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/partition"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/systemd"
)
type undoTestSuite struct {
@@ -63,7 +62,7 @@
si := snap.SideInfo{
OfficialName: "hello-snap",
- Revision: 14,
+ Revision: snap.R(14),
}
minInfo, err := SetupSnap(snapPath, &si, 0, &s.meter)
@@ -99,7 +98,7 @@
si := snap.SideInfo{
OfficialName: "kernel-snap",
- Revision: 140,
+ Revision: snap.R(140),
}
instDir, err := SetupSnap(snapPath, &si, 0, &s.meter)
@@ -112,125 +111,3 @@
l, _ = filepath.Glob(filepath.Join(bootloader.Dir(), "*"))
c.Assert(l, HasLen, 0)
}
-
-func (s *undoTestSuite) TestUndoForCopyData(c *C) {
- v1, err := makeInstalledMockSnap(`name: hello
-version: 1.0`, 11)
-
- c.Assert(err, IsNil)
- makeSnapActive(v1)
- // add some data
- datadir := filepath.Join(dirs.SnapDataDir, "hello/11")
- subdir := filepath.Join(datadir, "random-subdir")
- err = os.MkdirAll(subdir, 0755)
- c.Assert(err, IsNil)
- err = ioutil.WriteFile(filepath.Join(subdir, "random-file"), nil, 0644)
- c.Assert(err, IsNil)
-
- // pretend we install a new version
- v2, err := makeInstalledMockSnap(`name: hello
-version: 2.0`, 12)
-
- c.Assert(err, IsNil)
-
- sn1, err := NewInstalledSnap(v1)
- c.Assert(err, IsNil)
-
- sn, err := NewInstalledSnap(v2)
- c.Assert(err, IsNil)
-
- // copy data
- err = CopyData(sn.Info(), sn1.Info(), 0, &s.meter)
- c.Assert(err, IsNil)
- v2data := filepath.Join(dirs.SnapDataDir, "hello/12")
- l, _ := filepath.Glob(filepath.Join(v2data, "*"))
- c.Assert(l, HasLen, 1)
-
- UndoCopyData(sn.Info(), 0, &s.meter)
- l, _ = filepath.Glob(filepath.Join(v2data, "*"))
- c.Assert(l, HasLen, 0)
-
-}
-
-func (s *undoTestSuite) TestUndoForGenerateWrappers(c *C) {
- yaml, err := makeInstalledMockSnap(`name: hello
-version: 1.0
-apps:
- bin:
- command: bin
- svc:
- command: svc
- daemon: simple
-`, 11)
-
- c.Assert(err, IsNil)
-
- sn, err := NewInstalledSnap(yaml)
- c.Assert(err, IsNil)
-
- err = GenerateWrappers(sn.Info(), &s.meter)
- c.Assert(err, IsNil)
-
- l, err := filepath.Glob(filepath.Join(dirs.SnapBinariesDir, "*"))
- c.Assert(err, IsNil)
- c.Assert(l, HasLen, 1)
- l, err = filepath.Glob(filepath.Join(dirs.SnapServicesDir, "*.service"))
- c.Assert(err, IsNil)
- c.Assert(l, HasLen, 1)
-
- // undo via remove
- err = RemoveGeneratedWrappers(sn.Info(), &s.meter)
- l, err = filepath.Glob(filepath.Join(dirs.SnapBinariesDir, "*"))
- c.Assert(err, IsNil)
- c.Assert(l, HasLen, 0)
- l, err = filepath.Glob(filepath.Join(dirs.SnapServicesDir, "*.service"))
- c.Assert(err, IsNil)
- c.Assert(l, HasLen, 0)
-}
-
-func (s *undoTestSuite) TestUndoForUpdateCurrentSymlink(c *C) {
- v1yaml, err := makeInstalledMockSnap(`name: hello
-version: 1.0
-`, 11)
-
- c.Assert(err, IsNil)
- makeSnapActive(v1yaml)
-
- v2yaml, err := makeInstalledMockSnap(`name: hello
-version: 2.0
-`, 22)
-
- c.Assert(err, IsNil)
-
- v1, err := NewInstalledSnap(v1yaml)
- c.Assert(err, IsNil)
- v2, err := NewInstalledSnap(v2yaml)
- c.Assert(err, IsNil)
-
- err = UpdateCurrentSymlink(v2.Info(), &s.meter)
- c.Assert(err, IsNil)
-
- v1MountDir := v1.Info().MountDir()
- v2MountDir := v2.Info().MountDir()
- v2DataDir := v2.Info().DataDir()
- currentActiveSymlink := filepath.Join(v2MountDir, "..", "current")
- currentActiveDir, err := filepath.EvalSymlinks(currentActiveSymlink)
- c.Assert(err, IsNil)
- c.Assert(currentActiveDir, Equals, v2MountDir)
-
- currentDataSymlink := filepath.Join(filepath.Dir(v2DataDir), "current")
- currentDataDir, err := filepath.EvalSymlinks(currentDataSymlink)
- c.Assert(err, IsNil)
- c.Assert(currentDataDir, Matches, `.*/22`)
-
- // undo is just update again
- err = UpdateCurrentSymlink(v1.Info(), &s.meter)
- currentActiveDir, err = filepath.EvalSymlinks(currentActiveSymlink)
- c.Assert(err, IsNil)
- c.Assert(currentActiveDir, Equals, v1MountDir)
-
- currentDataDir, err = filepath.EvalSymlinks(currentDataSymlink)
- c.Assert(err, IsNil)
- c.Assert(currentDataDir, Matches, `.*/11`)
-
-}
diff -Nru snapd-2.0.5/snappy/utils.go snapd-2.0.8/snappy/utils.go
--- snapd-2.0.5/snappy/utils.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/snappy/utils.go 2016-06-08 05:58:01.000000000 +0000
@@ -23,9 +23,10 @@
"fmt"
"os"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/snap/snapenv"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snapenv"
)
// takes a directory and removes the global root, this is needed
@@ -47,21 +48,21 @@
// The returned environment contains additional SNAP_* variables that
// are required when calling a meta/hook/ script and that will override
// any already existing SNAP_* variables in os.Environment()
-func makeSnapHookEnv(snap *Snap) (env []string) {
+func makeSnapHookEnv(sn *Snap) (env []string) {
desc := struct {
SnapName string
SnapArch string
SnapPath string
Version string
- Revision int
+ Revision snap.Revision
UdevAppName string
}{
- snap.Name(),
+ sn.Name(),
arch.UbuntuArchitecture(),
- snap.Info().MountDir(),
- snap.Version(),
- snap.Revision(),
- snap.Name(),
+ sn.Info().MountDir(),
+ sn.Version(),
+ sn.Revision(),
+ sn.Name(),
}
vars := snapenv.GetBasicSnapEnvVars(desc)
diff -Nru snapd-2.0.5/store/details.go snapd-2.0.8/store/details.go
--- snapd-2.0.5/store/details.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/store/details.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,7 +20,7 @@
package store
import (
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/snap"
)
// snapDetails encapsulates the data sent to us from the store.
@@ -42,7 +42,7 @@
Prices map[string]float64 `json:"prices,omitempty"`
Publisher string `json:"publisher,omitempty"`
RatingsAverage float64 `json:"ratings_average,omitempty"`
- Revision int `json:"revision"`
+ Revision snap.Revision `json:"revision"`
SnapID string `json:"snap_id"`
SupportURL string `json:"support_url"`
Title string `json:"title"`
@@ -51,6 +51,7 @@
// FIXME: the store should return "developer" to us instead of
// origin
- Developer string `json:"origin" yaml:"origin"`
- Private bool `json:"private" yaml:"private"`
+ Developer string `json:"origin" yaml:"origin"`
+ Private bool `json:"private" yaml:"private"`
+ Confinement string `json:"confinement" yaml:"confinement"`
}
diff -Nru snapd-2.0.5/store/store.go snapd-2.0.8/store/store.go
--- snapd-2.0.5/store/store.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/store/store.go 2016-06-08 05:58:01.000000000 +0000
@@ -34,12 +34,12 @@
"strings"
"sync"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/release"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/release"
+ "github.com/snapcore/snapd/snap"
)
// TODO: better/shorter names are probably in order once fewer legacy places are using this
@@ -56,6 +56,7 @@
info.Architectures = d.Architectures
info.Type = d.Type
info.Version = d.Version
+ info.Epoch = "0"
info.OfficialName = d.Name
info.SnapID = d.SnapID
info.Revision = d.Revision
@@ -167,7 +168,7 @@
v.Set("fields", strings.Join(getStructFields(snapDetails{}), ","))
defaultConfig.SearchURI.RawQuery = v.Encode()
- defaultConfig.BulkURI, err = storeBaseURI.Parse("click-metadata")
+ defaultConfig.BulkURI, err = storeBaseURI.Parse("metadata")
if err != nil {
panic(err)
}
@@ -212,20 +213,20 @@
}
// small helper that sets the correct http headers for the ubuntu store
-func (s *SnapUbuntuStoreRepository) applyUbuntuStoreHeaders(req *http.Request, accept string, auther Authenticator) {
+func (s *SnapUbuntuStoreRepository) setUbuntuStoreHeaders(req *http.Request, channel string, auther Authenticator) {
if auther != nil {
auther.Authenticate(req)
}
- if accept == "" {
- accept = "application/hal+json"
- }
- req.Header.Set("Accept", accept)
-
+ req.Header.Set("Accept", "application/hal+json,application/json")
req.Header.Set("X-Ubuntu-Architecture", string(arch.UbuntuArchitecture()))
req.Header.Set("X-Ubuntu-Release", release.Series)
req.Header.Set("X-Ubuntu-Wire-Protocol", UbuntuCoreWireProtocol)
+ if channel != "" {
+ req.Header.Set("X-Ubuntu-Device-Channel", channel)
+ }
+
if s.storeID != "" {
req.Header.Set("X-Ubuntu-Store", s.storeID)
}
@@ -295,8 +296,7 @@
return nil, err
}
- s.applyUbuntuStoreHeaders(req, "", auther)
- req.Header.Set("X-Ubuntu-Device-Channel", channel)
+ s.setUbuntuStoreHeaders(req, channel, auther)
resp, err := s.client.Do(req)
if err != nil {
@@ -424,8 +424,7 @@
}
// set headers
- s.applyUbuntuStoreHeaders(req, "", auther)
- req.Header.Set("X-Ubuntu-Device-Channel", channel)
+ s.setUbuntuStoreHeaders(req, channel, auther)
resp, err := s.client.Do(req)
if err != nil {
@@ -476,9 +475,9 @@
}
-// FindSnaps finds (installable) snaps from the store, matching the
+// Find finds (installable) snaps from the store, matching the
// given search term.
-func (s *SnapUbuntuStoreRepository) FindSnaps(searchTerm string, channel string, auther Authenticator) ([]*snap.Info, error) {
+func (s *SnapUbuntuStoreRepository) Find(searchTerm string, channel string, auther Authenticator) ([]*snap.Info, error) {
if channel == "" {
channel = "stable"
}
@@ -494,8 +493,7 @@
}
// set headers
- s.applyUbuntuStoreHeaders(req, "", auther)
- req.Header.Set("X-Ubuntu-Device-Channel", channel)
+ s.setUbuntuStoreHeaders(req, channel, auther)
resp, err := s.client.Do(req)
if err != nil {
@@ -533,11 +531,73 @@
return snaps, nil
}
-// Updates returns the available updates for a list of snap identified by fullname with channel.
-func (s *SnapUbuntuStoreRepository) Updates(installed []string, auther Authenticator) (snaps []*snap.Info, err error) {
- // XXX: uses obsolete end point!
+// RefreshCandidate contains information for the store about the currently
+// installed snap so that the store can decide what update we should see
+type RefreshCandidate struct {
+ SnapID string
+ Revision snap.Revision
+ Epoch string
+ DevMode bool
+
+ // the desired channel
+ Channel string
+}
+
+// the exact bits that we need to send to the store
+type currentSnapJson struct {
+ SnapID string `json:"snap_id"`
+ Channel string `json:"channel"`
+ Revision int `json:"revision,omitempty"`
+ Epoch string `json:"epoch"`
+
+ // The store expects a "confinement" value {"strict", "devmode"}.
+ // We map this accordingly from our devmode bool, we do not
+ // use the value of the current snap as we are interested in the
+ // users intention, not the actual value of the snap itself.
+ Confinement snap.ConfinementType `json:"confinement"`
+}
+
+type metadataWrapper struct {
+ Snaps []currentSnapJson `json:"snaps"`
+ Fields []string `json:"fields"`
+}
+
+// ListRefresh returns the available updates for a list of snap identified by fullname with channel.
+func (s *SnapUbuntuStoreRepository) ListRefresh(installed []*RefreshCandidate, auther Authenticator) (snaps []*snap.Info, err error) {
+
+ candidateMap := map[string]*RefreshCandidate{}
+ currentSnaps := make([]currentSnapJson, 0, len(installed))
+ for _, cs := range installed {
+ revision := cs.Revision.N
+ if !cs.Revision.Store() {
+ revision = 0
+ }
+ // the store gets confused if we send snaps without a snapid
+ // (like local ones)
+ if cs.SnapID == "" {
+ continue
+ }
- jsonData, err := json.Marshal(map[string][]string{"name": installed})
+ confinement := snap.StrictConfinement
+ if cs.DevMode {
+ confinement = snap.DevmodeConfinement
+ }
+
+ currentSnaps = append(currentSnaps, currentSnapJson{
+ SnapID: cs.SnapID,
+ Channel: cs.Channel,
+ Confinement: confinement,
+ Epoch: cs.Epoch,
+ Revision: revision,
+ })
+ candidateMap[cs.SnapID] = cs
+ }
+
+ // build input for the updates endpoint
+ jsonData, err := json.Marshal(metadataWrapper{
+ Snaps: currentSnaps,
+ Fields: []string{"snap_id", "package_name", "revision", "version", "download_url"},
+ })
if err != nil {
return nil, err
}
@@ -549,7 +609,7 @@
// set headers
// the updates call is a special snowflake right now
// (see LP: #1427155)
- s.applyUbuntuStoreHeaders(req, "application/json", auther)
+ s.setUbuntuStoreHeaders(req, "", auther)
resp, err := s.client.Do(req)
if err != nil {
@@ -557,15 +617,20 @@
}
defer resp.Body.Close()
- var updateData []snapDetails
+ var updateData searchResults
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&updateData); err != nil {
return nil, err
}
- res := make([]*snap.Info, len(updateData))
- for i, rsnap := range updateData {
- res[i] = infoFromRemote(rsnap)
+ res := make([]*snap.Info, 0, len(updateData.Payload.Packages))
+ for _, rsnap := range updateData.Payload.Packages {
+ // the store also gives us identical revisions, filter those
+ // out, we are not interested
+ if rsnap.Revision == candidateMap[rsnap.SnapID].Revision {
+ continue
+ }
+ res = append(res, infoFromRemote(rsnap))
}
s.checkStoreResponse(resp)
@@ -600,7 +665,7 @@
if err != nil {
return "", err
}
- s.applyUbuntuStoreHeaders(req, "", auther)
+ s.setUbuntuStoreHeaders(req, "", auther)
if err := download(remoteSnap.Name(), w, req, pbar); err != nil {
return "", err
diff -Nru snapd-2.0.5/store/store_test.go snapd-2.0.8/store/store_test.go
--- snapd-2.0.5/store/store_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/store/store_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -33,12 +33,12 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/asserts"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
)
type remoteRepoTestSuite struct {
@@ -172,15 +172,15 @@
req, err := http.NewRequest("GET", "http://example.com", nil)
c.Assert(err, IsNil)
- t.store.applyUbuntuStoreHeaders(req, "", nil)
+ t.store.setUbuntuStoreHeaders(req, "", nil)
- c.Assert(req.Header.Get("X-Ubuntu-Release"), Equals, "16")
- c.Check(req.Header.Get("Accept"), Equals, "application/hal+json")
+ c.Check(req.Header.Get("X-Ubuntu-Release"), Equals, "16")
+ c.Check(req.Header.Get("X-Ubuntu-Device-Channel"), Equals, "")
- t.store.applyUbuntuStoreHeaders(req, "application/json", nil)
+ t.store.setUbuntuStoreHeaders(req, "chan", nil)
- c.Check(req.Header.Get("Accept"), Equals, "application/json")
- c.Assert(req.Header.Get("Authorization"), Equals, "")
+ c.Check(req.Header.Get("Authorization"), Equals, "")
+ c.Check(req.Header.Get("X-Ubuntu-Device-Channel"), Equals, "chan")
}
const (
@@ -331,7 +331,7 @@
c.Assert(err, IsNil)
c.Check(result.Name(), Equals, "hello-world")
c.Check(result.Architectures, DeepEquals, []string{"all"})
- c.Check(result.Revision, Equals, 25)
+ c.Check(result.Revision, Equals, snap.R(25))
c.Check(result.SnapID, Equals, helloWorldSnapID)
c.Check(result.Developer, Equals, "canonical")
c.Check(result.Version, Equals, "6.0")
@@ -343,8 +343,13 @@
c.Assert(result.Prices, DeepEquals, map[string]float64{"USD": 1.23})
c.Check(result.MustBuy, Equals, true)
+ // Make sure the epoch (currently not sent by the store) defaults to "0"
+ c.Check(result.Epoch, Equals, "0")
+
c.Check(repo.SuggestedCurrency(), Equals, "GBP")
c.Check(result.Private, Equals, true)
+
+ c.Check(snap.Validate(result), IsNil)
}
func (t *remoteRepoTestSuite) TestUbuntuStoreRepositoryDetailsSetsAuth(c *C) {
@@ -558,7 +563,7 @@
repo := NewUbuntuStoreSnapRepository(&cfg, "")
c.Assert(repo, NotNil)
- snaps, err := repo.FindSnaps("hello", "", nil)
+ snaps, err := repo.Find("hello", "", nil)
c.Assert(err, IsNil)
c.Assert(snaps, HasLen, 1)
c.Check(snaps[0].Name(), Equals, "hello-world")
@@ -583,7 +588,7 @@
repo := NewUbuntuStoreSnapRepository(&cfg, "")
c.Assert(repo, NotNil)
- snaps, err := repo.FindSnaps("hello", "", nil)
+ snaps, err := repo.Find("hello", "", nil)
c.Check(err, ErrorMatches, `received an unexpected http response code \(418 I'm a teapot\) when trying to search via "http://[^?]+\?q=hello"`)
c.Check(snaps, HasLen, 0)
}
@@ -605,7 +610,7 @@
repo := NewUbuntuStoreSnapRepository(&cfg, "")
c.Assert(repo, NotNil)
- snaps, err := repo.FindSnaps("hello", "", nil)
+ snaps, err := repo.Find("hello", "", nil)
c.Check(err, ErrorMatches, `received an unexpected content type \("text/plain[^"]+"\) when trying to search via "http://[^?]+\?q=hello"`)
c.Check(snaps, HasLen, 0)
}
@@ -628,7 +633,7 @@
repo := NewUbuntuStoreSnapRepository(&cfg, "")
c.Assert(repo, NotNil)
- snaps, err := repo.FindSnaps("hello", "", nil)
+ snaps, err := repo.Find("hello", "", nil)
c.Check(err, ErrorMatches, `cannot decode reply \(got invalid character.*\) when trying to search via "http://[^?]+\?q=hello"`)
c.Check(snaps, HasLen, 0)
}
@@ -669,7 +674,7 @@
c.Assert(repo, NotNil)
authenticator := &fakeAuthenticator{}
- snaps, err := repo.FindSnaps("foo", "", authenticator)
+ snaps, err := repo.Find("foo", "", authenticator)
c.Assert(err, IsNil)
c.Assert(snaps, HasLen, 1)
c.Check(snaps[0].SnapID, Equals, helloWorldSnapID)
@@ -713,7 +718,7 @@
c.Assert(repo, NotNil)
authenticator := &fakeAuthenticator{}
- snaps, err := repo.FindSnaps("foo", "", authenticator)
+ snaps, err := repo.Find("foo", "", authenticator)
c.Assert(err, IsNil)
// Check that we log an error.
@@ -727,33 +732,47 @@
}
/* acquired via:
-curl -s --data-binary '{"name":["8nzc1x4iim2xj1g2ul64.chipaca"]}' -H 'content-type: application/json' https://search.apps.ubuntu.com/api/v1/click-metadata
+(against staging "hello-world"):
+$ $ curl -s --data-binary '{"snaps":[{"snap_id":"JtwEnisYi8Mmk51vNLZPSOwSOFLwGdhs","channel":"stable","revision":6}],"fields":["snap_id","package_name","revision","version","download_url"]}' -H 'content-type: application/json' https://search.apps.staging.ubuntu.com/api/v1/metadata|python -m json.tool
+
+(against production "hello-world")
+$ curl -s --data-binary '{"snaps":[{"snap_id":"buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ","channel":"stable","revision":25,"confinement":"strict"}],"fields":["snap_id","package_name","revision","version","download_url"]}' -H 'content-type: application/json' https://search.apps.ubuntu.com/api/v1/metadata
*/
-const MockUpdatesJSON = `[
- {
- "status": "Published",
- "name": "8nzc1x4iim2xj1g2ul64.chipaca",
- "package_name": "8nzc1x4iim2xj1g2ul64",
- "snap_id": "1e21e12ex4iim2xj1g2ul6f12f1",
- "origin": "chipaca",
- "changelog": "",
- "icon_url": "https://myapps.developer.ubuntu.com/site_media/appmedia/2015/04/hello.svg_Dlrd3L4.png",
- "title": "Returns for store credit only.",
- "binary_filesize": 65375,
- "anon_download_url": "https://public.apps.ubuntu.com/anon/download/chipaca/8nzc1x4iim2xj1g2ul64.chipaca/8nzc1x4iim2xj1g2ul64.chipaca_42_all.snap",
- "allow_unauthenticated": true,
- "revision": 3,
- "version": "42",
- "download_url": "https://public.apps.ubuntu.com/download/chipaca/8nzc1x4iim2xj1g2ul64.chipaca/8nzc1x4iim2xj1g2ul64.chipaca_42_all.snap",
- "download_sha512": "5364253e4a988f4f5c04380086d542f410455b97d48cc6c69ca2a5877d8aef2a6b2b2f83ec4f688cae61ebc8a6bf2cdbd4dbd8f743f0522fc76540429b79df42"
+var MockUpdatesJSON = fmt.Sprintf(`
+{
+ "_embedded": {
+ "clickindex:package": [
+ {
+ "_links": {
+ "self": {
+ "href": "https://search.apps.staging.ubuntu.com/api/v1/package/%[1]s"
+ }
+ },
+ "download_url": "https://public.apps.staging.ubuntu.com/download-snap/%[1].snap",
+ "package_name": "hello-world",
+ "revision": 6,
+ "snap_id": "%[1]s",
+ "version": "16.04-1"
+ }
+ ]
+ },
+ "_links": {
+ "curies": [
+ {
+ "href": "https://wiki.ubuntu.com/AppStore/Interfaces/ClickPackageIndex#reltype_{rel}",
+ "name": "clickindex",
+ "templated": true
+ }
+ ]
}
-]`
+}
+`, helloWorldSnapID)
-func (t *remoteRepoTestSuite) TestUbuntuStoreRepositoryUpdates(c *C) {
+func (t *remoteRepoTestSuite) TestUbuntuStoreRepositoryListRefresh(c *C) {
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
jsonReq, err := ioutil.ReadAll(r.Body)
c.Assert(err, IsNil)
- c.Assert(string(jsonReq), Equals, `{"name":["`+funkyAppName+`"]}`)
+ c.Assert(string(jsonReq), Equals, `{"snaps":[{"snap_id":"`+helloWorldSnapID+`","channel":"stable","revision":1,"epoch":"0","confinement":"strict"}],"fields":["snap_id","package_name","revision","version","download_url"]}`)
io.WriteString(w, MockUpdatesJSON)
}))
@@ -769,12 +788,52 @@
repo := NewUbuntuStoreSnapRepository(&cfg, "")
c.Assert(repo, NotNil)
- results, err := repo.Updates([]string{funkyAppName}, nil)
+ results, err := repo.ListRefresh([]*RefreshCandidate{
+ {
+ SnapID: helloWorldSnapID,
+ Channel: "stable",
+ Revision: snap.R(1),
+ Epoch: "0",
+ DevMode: false,
+ },
+ }, nil)
c.Assert(err, IsNil)
c.Assert(results, HasLen, 1)
- c.Assert(results[0].Name(), Equals, funkyAppName)
- c.Assert(results[0].Revision, Equals, 3)
- c.Assert(results[0].Version, Equals, "42")
+ c.Assert(results[0].Name(), Equals, "hello-world")
+ c.Assert(results[0].Revision, Equals, snap.R(6))
+ c.Assert(results[0].Version, Equals, "16.04-1")
+}
+
+func (t *remoteRepoTestSuite) TestUbuntuStoreRepositoryUpdateNotSendLocalRevs(c *C) {
+ mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ jsonReq, err := ioutil.ReadAll(r.Body)
+ c.Assert(err, IsNil)
+ c.Assert(string(jsonReq), Equals, `{"snaps":[{"snap_id":"`+helloWorldSnapID+`","channel":"stable","epoch":"0","confinement":"devmode"}],"fields":["snap_id","package_name","revision","version","download_url"]}`)
+ io.WriteString(w, MockUpdatesJSON)
+ }))
+
+ c.Assert(mockServer, NotNil)
+ defer mockServer.Close()
+
+ var err error
+ bulkURI, err := url.Parse(mockServer.URL + "/updates/")
+ c.Assert(err, IsNil)
+ cfg := SnapUbuntuStoreConfig{
+ BulkURI: bulkURI,
+ }
+ repo := NewUbuntuStoreSnapRepository(&cfg, "")
+ c.Assert(repo, NotNil)
+
+ _, err = repo.ListRefresh([]*RefreshCandidate{
+ {
+ SnapID: helloWorldSnapID,
+ Channel: "stable",
+ Revision: snap.R(-2),
+ Epoch: "0",
+ DevMode: true,
+ },
+ }, nil)
+ c.Assert(err, IsNil)
}
func (t *remoteRepoTestSuite) TestUbuntuStoreRepositoryUpdatesSetsAuth(c *C) {
@@ -785,7 +844,7 @@
jsonReq, err := ioutil.ReadAll(r.Body)
c.Assert(err, IsNil)
- c.Assert(string(jsonReq), Equals, `{"name":["`+funkyAppName+`"]}`)
+ c.Assert(string(jsonReq), Equals, `{"snaps":[{"snap_id":"`+helloWorldSnapID+`","channel":"stable","revision":1,"epoch":"0","confinement":"strict"}],"fields":["snap_id","package_name","revision","version","download_url"]}`)
io.WriteString(w, MockUpdatesJSON)
}))
@@ -802,7 +861,15 @@
c.Assert(repo, NotNil)
authenticator := &fakeAuthenticator{}
- _, err = repo.Updates([]string{funkyAppName}, authenticator)
+ _, err = repo.ListRefresh([]*RefreshCandidate{
+ {
+ SnapID: helloWorldSnapID,
+ Channel: "stable",
+ Revision: snap.R(1),
+ Epoch: "0",
+ DevMode: false,
+ },
+ }, authenticator)
c.Assert(err, IsNil)
}
@@ -860,7 +927,7 @@
func (t *remoteRepoTestSuite) TestDefaultConfig(c *C) {
c.Check(strings.HasPrefix(defaultConfig.SearchURI.String(), "https://search.apps.ubuntu.com/api/v1/search?"), Equals, true)
- c.Check(strings.HasPrefix(defaultConfig.BulkURI.String(), "https://search.apps.ubuntu.com/api/v1/click-metadata?"), Equals, true)
+ c.Check(strings.HasPrefix(defaultConfig.BulkURI.String(), "https://search.apps.ubuntu.com/api/v1/metadata?"), Equals, true)
c.Check(defaultConfig.AssertionsURI.String(), Equals, "https://assertions.ubuntu.com/v1/assertions/")
}
diff -Nru snapd-2.0.5/systemd/escape_test.go snapd-2.0.8/systemd/escape_test.go
--- snapd-2.0.5/systemd/escape_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/systemd/escape_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -22,7 +22,7 @@
import (
. "gopkg.in/check.v1"
- . "github.com/ubuntu-core/snappy/systemd"
+ . "github.com/snapcore/snapd/systemd"
)
func (s *SystemdTestSuite) TestEscape(c *C) {
diff -Nru snapd-2.0.5/systemd/systemd.go snapd-2.0.8/systemd/systemd.go
--- snapd-2.0.5/systemd/systemd.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/systemd/systemd.go 2016-06-08 05:58:01.000000000 +0000
@@ -31,8 +31,8 @@
"strconv"
"time"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
)
var (
@@ -412,16 +412,21 @@
}
func (s *systemd) WriteMountUnitFile(name, what, where string) (string, error) {
+ extra := ""
+ if osutil.IsDirectory(what) {
+ extra = "Options=bind\nType=none\n"
+ }
+
c := fmt.Sprintf(`[Unit]
-Description=Squashfs mount unit for %s
+Description=Mount unit for %s
[Mount]
What=%s
Where=%s
-
+%s
[Install]
WantedBy=multi-user.target
-`, name, what, where)
+`, name, what, where, extra)
mu := MountUnitPath(where, "mount")
return filepath.Base(mu), osutil.AtomicWriteFile(mu, []byte(c), 0644, 0)
diff -Nru snapd-2.0.5/systemd/systemd_test.go snapd-2.0.8/systemd/systemd_test.go
--- snapd-2.0.5/systemd/systemd_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/systemd/systemd_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -20,6 +20,7 @@
package systemd_test
import (
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -29,8 +30,8 @@
. "gopkg.in/check.v1"
"gopkg.in/yaml.v2"
- "github.com/ubuntu-core/snappy/dirs"
- . "github.com/ubuntu-core/snappy/systemd"
+ "github.com/snapcore/snapd/dirs"
+ . "github.com/snapcore/snapd/systemd"
)
type testreporter struct {
@@ -278,22 +279,51 @@
}
func (s *SystemdTestSuite) TestWriteMountUnit(c *C) {
- mountUnitName, err := New("", nil).WriteMountUnitFile("foo", "/var/lib/snappy/snaps/foo_1.0.snap", "/apps/foo/1.0")
+ mockSnapPath := filepath.Join(c.MkDir(), "/var/lib/snappy/snaps/foo_1.0.snap")
+ err := os.MkdirAll(filepath.Dir(mockSnapPath), 0755)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(mockSnapPath, nil, 0644)
+ c.Assert(err, IsNil)
+
+ mountUnitName, err := New("", nil).WriteMountUnitFile("foo", mockSnapPath, "/apps/foo/1.0")
+ c.Assert(err, IsNil)
+ defer os.Remove(mountUnitName)
+
+ mount, err := ioutil.ReadFile(filepath.Join(dirs.SnapServicesDir, mountUnitName))
+ c.Assert(err, IsNil)
+ c.Assert(string(mount), Equals, fmt.Sprintf(`[Unit]
+Description=Mount unit for foo
+
+[Mount]
+What=%s
+Where=/apps/foo/1.0
+
+[Install]
+WantedBy=multi-user.target
+`, mockSnapPath))
+}
+
+func (s *SystemdTestSuite) TestWriteMountUnitForDirs(c *C) {
+ // a directory instead of a file produces a different output
+ snapDir := c.MkDir()
+ mountUnitName, err := New("", nil).WriteMountUnitFile("foodir", snapDir, "/apps/foo/1.0")
c.Assert(err, IsNil)
defer os.Remove(mountUnitName)
mount, err := ioutil.ReadFile(filepath.Join(dirs.SnapServicesDir, mountUnitName))
c.Assert(err, IsNil)
- c.Assert(string(mount), Equals, `[Unit]
-Description=Squashfs mount unit for foo
+ c.Assert(string(mount), Equals, fmt.Sprintf(`[Unit]
+Description=Mount unit for foodir
[Mount]
-What=/var/lib/snappy/snaps/foo_1.0.snap
+What=%s
Where=/apps/foo/1.0
+Options=bind
+Type=none
[Install]
WantedBy=multi-user.target
-`)
+`, snapDir))
}
func (s *SystemdTestSuite) TestRestartCondUnmarshal(c *C) {
diff -Nru snapd-2.0.5/.tarmac.sh snapd-2.0.8/.tarmac.sh
--- snapd-2.0.5/.tarmac.sh 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/.tarmac.sh 2016-06-08 05:58:01.000000000 +0000
@@ -7,8 +7,8 @@
trap 'rm -rf "$GOPATH"' EXIT
# this is a hack, but not sure tarmac is golang friendly
-mkdir -p $GOPATH/src/github.com/ubuntu-core/snappy
-cp -a . $GOPATH/src/github.com/ubuntu-core/snappy/
-cd $GOPATH/src/github.com/ubuntu-core/snappy
+mkdir -p $GOPATH/src/github.com/snapcore/snapd
+cp -a . $GOPATH/src/github.com/snapcore/snapd/
+cd $GOPATH/src/github.com/snapcore/snapd
sh -v ./run-checks
diff -Nru snapd-2.0.5/.travis.yml snapd-2.0.8/.travis.yml
--- snapd-2.0.5/.travis.yml 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/.travis.yml 2016-06-08 05:58:01.000000000 +0000
@@ -7,7 +7,7 @@
global:
# Encrypted Coveralls token. The secret token for your repository can be found at the bottom of
# your repository's page on Coveralls. To encrypt it, install the travis gem and run:
- # travis encrypt -r ubuntu-core/snappy COVERALLS_TOKEN=$secret_token
+ # travis encrypt -r snapcore/snapd COVERALLS_TOKEN=$secret_token
- secure: "bHMAmu1F32uc3EXYuK8VnxK3x57aZTr0L4f4J1SKLKKkCy9khvwfBRXP+mlBtNzTjzN9TPYYXc5M6JYJKlM9a8ylu+kzjJBzpW6oI01yKskJuzSr7QbQl9SPoSxYvIZC38df+pJV7dCBtiK/ikXWixRtf316VaQOkaVYcLYs5lYvSrPTGYrEr90CHH2ZlVgUASdee3t6Ew7jIbs0MKRz1AOtrU2N2OZj9SmLa3PBB3syMpamf5aJW/kDR7JrRCLHdbTMDtGk+B8klPKofhOEGzplAqnzeBdMS2yqZ+qBH85w40NX3HEyQryzdidod1VmMfj9AUIgsy8rdfwWjjp0GxdSG9sX4KBi8sgtBfq4S7VtluWPQwe0/l6y3spZv7agNzVej6fM+hongFlpvuXMxGHuiqbkln4cx8KWD+jr5eljdinbxQKXHVn/xOiGLl4rcVMgVaYna/t6tVSBmOD0G45Q/UBu1b+AxdchDzMzv+A4ASwRJwYHUPj1SIlducd+VfvucVDiczF9CqnquCwgoJKN5vufxyz4wPgqnwhXwTd1+f+lROoB3gOE0aQya8wSGIulqZO5DbHkCO/gFMKRTxNIk9FM+CZwwFgPiqlOeY88nnHK1tY/ShIihK1jV6BSl1UkZEn91h64/0zh22YJ3/yp3mP30L8Q5MwgsXdeZNI="
matrix:
- TEST_SUITE="--static"
@@ -16,6 +16,7 @@
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq squashfs-tools
+ - sudo apt-get install -qq gnupg
install:
- echo "Skip. Install is done by the test script."
script: sh -v ./run-checks $TEST_SUITE
diff -Nru snapd-2.0.5/update-pot snapd-2.0.8/update-pot
--- snapd-2.0.5/update-pot 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/update-pot 2016-06-08 05:58:01.000000000 +0000
@@ -11,7 +11,7 @@
fi
# ensure we have our xgettext-go
-go install github.com/ubuntu-core/snappy/i18n/xgettext-go
+go install github.com/snapcore/snapd/i18n/xgettext-go
$GOPATH/bin/xgettext-go \
-o "$OUTPUT" \
diff -Nru snapd-2.0.5/wrappers/binaries_gen_test.go snapd-2.0.8/wrappers/binaries_gen_test.go
--- snapd-2.0.5/wrappers/binaries_gen_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/wrappers/binaries_gen_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,9 +24,9 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/wrappers"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/wrappers"
)
type binariesWrapperGenSuite struct{}
@@ -61,7 +61,7 @@
info := &snap.Info{}
info.SuggestedName = "pastebinit"
info.Version = "1.4.0.0.1"
- info.Revision = 44
+ info.Revision = snap.R(44)
binary := &snap.AppInfo{
Snap: info,
Name: "pastebinit",
diff -Nru snapd-2.0.5/wrappers/binaries.go snapd-2.0.8/wrappers/binaries.go
--- snapd-2.0.5/wrappers/binaries.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/wrappers/binaries.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,12 +26,12 @@
"strings"
"text/template"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snapenv"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snapenv"
)
// Doesn't need to handle complications like internal quotes, just needs to
@@ -72,7 +72,7 @@
SnapArch string
SnapPath string
Version string
- Revision int
+ Revision snap.Revision
Home string
}{
App: app,
diff -Nru snapd-2.0.5/wrappers/binaries_test.go snapd-2.0.8/wrappers/binaries_test.go
--- snapd-2.0.5/wrappers/binaries_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/wrappers/binaries_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,11 +28,11 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/wrappers"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/wrappers"
)
func TestWrappers(t *testing.T) { TestingT(t) }
@@ -67,7 +67,7 @@
`
func (s *binariesTestSuite) TestAddSnapBinariesAndRemove(c *C) {
- info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: 11})
+ info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(11)})
err := wrappers.AddSnapBinaries(info)
c.Assert(err, IsNil)
diff -Nru snapd-2.0.5/wrappers/desktop.go snapd-2.0.8/wrappers/desktop.go
--- snapd-2.0.5/wrappers/desktop.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/wrappers/desktop.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,9 +28,9 @@
"path/filepath"
"strings"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
)
// valid simple prefixes
diff -Nru snapd-2.0.5/wrappers/desktop_test.go snapd-2.0.8/wrappers/desktop_test.go
--- snapd-2.0.5/wrappers/desktop_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/wrappers/desktop_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -26,11 +26,11 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/wrappers"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/wrappers"
)
type desktopSuite struct {
@@ -62,7 +62,7 @@
expectedDesktopFilePath := filepath.Join(dirs.SnapDesktopFilesDir, "foo_foobar.desktop")
c.Assert(osutil.FileExists(expectedDesktopFilePath), Equals, false)
- info := snaptest.MockSnap(c, desktopAppYaml, &snap.SideInfo{Revision: 11})
+ info := snaptest.MockSnap(c, desktopAppYaml, &snap.SideInfo{Revision: snap.R(11)})
// generate .desktop file in the package baseDir
baseDir := info.MountDir()
@@ -99,7 +99,7 @@
var _ = Suite(&sanitizeDesktopFileSuite{})
func (s *sanitizeDesktopFileSuite) TestSanitizeIgnoreNotWhitelisted(c *C) {
- snap := &snap.Info{SideInfo: snap.SideInfo{OfficialName: "foo", Revision: 12}}
+ snap := &snap.Info{SideInfo: snap.SideInfo{OfficialName: "foo", Revision: snap.R(12)}}
desktopContent := []byte(`[Desktop Entry]
Name=foo
UnknownKey=baz
diff -Nru snapd-2.0.5/wrappers/services_gen_test.go snapd-2.0.8/wrappers/services_gen_test.go
--- snapd-2.0.5/wrappers/services_gen_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/wrappers/services_gen_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -24,11 +24,11 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/systemd"
- "github.com/ubuntu-core/snappy/timeout"
- "github.com/ubuntu-core/snappy/wrappers"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/systemd"
+ "github.com/snapcore/snapd/timeout"
+ "github.com/snapcore/snapd/wrappers"
)
type servicesWrapperGenSuite struct{}
@@ -98,7 +98,7 @@
`
info, err := snap.InfoFromSnapYaml([]byte(yamlText))
c.Assert(err, IsNil)
- info.Revision = 44
+ info.Revision = snap.R(44)
app := info.Apps["app"]
generatedWrapper, err := wrappers.GenerateSnapServiceFile(app)
@@ -118,7 +118,7 @@
info, err := snap.InfoFromSnapYaml([]byte(yamlText))
c.Assert(err, IsNil)
- info.Revision = 44
+ info.Revision = snap.R(44)
app := info.Apps["app"]
wrapperText, err := wrappers.GenerateSnapServiceFile(app)
@@ -133,7 +133,7 @@
Snap: &snap.Info{
SuggestedName: "xkcd-webserver",
Version: "0.3.4",
- SideInfo: snap.SideInfo{Revision: 44},
+ SideInfo: snap.SideInfo{Revision: snap.R(44)},
},
Name: "xkcd-webserver",
Command: "bin/foo start",
@@ -153,7 +153,7 @@
Snap: &snap.Info{
SuggestedName: "xkcd-webserver",
Version: "0.3.4",
- SideInfo: snap.SideInfo{Revision: 44},
+ SideInfo: snap.SideInfo{Revision: snap.R(44)},
},
Name: "xkcd-webserver",
Command: "bin/foo start\n",
@@ -184,7 +184,7 @@
info, err := snap.InfoFromSnapYaml([]byte(yamlText))
c.Assert(err, IsNil)
- info.Revision = 44
+ info.Revision = snap.R(44)
app := info.Apps["app"]
wrapperText, err := wrappers.GenerateSnapServiceFile(app)
@@ -198,7 +198,7 @@
Snap: &snap.Info{
SideInfo: snap.SideInfo{
OfficialName: "xkcd-webserver",
- Revision: 44,
+ Revision: snap.R(44),
},
Version: "0.3.4",
},
@@ -232,7 +232,7 @@
Snap: &snap.Info{
SideInfo: snap.SideInfo{
OfficialName: "xkcd-webserver",
- Revision: 44,
+ Revision: snap.R(44),
},
Version: "0.3.4",
},
@@ -253,7 +253,7 @@
Snap: &snap.Info{
SideInfo: snap.SideInfo{
OfficialName: "xkcd-webserver",
- Revision: 44,
+ Revision: snap.R(44),
},
Version: "0.3.4",
},
@@ -273,6 +273,7 @@
func (s *servicesWrapperGenSuite) TestGenerateSnapSocketFileMode(c *C) {
srv := &snap.AppInfo{
+ Name: "foo",
Snap: &snap.Info{},
}
diff -Nru snapd-2.0.5/wrappers/services.go snapd-2.0.8/wrappers/services.go
--- snapd-2.0.5/wrappers/services.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/wrappers/services.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,14 +28,14 @@
"text/template"
"time"
- "github.com/ubuntu-core/snappy/arch"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/logger"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snapenv"
- "github.com/ubuntu-core/snappy/systemd"
- "github.com/ubuntu-core/snappy/timeout"
+ "github.com/snapcore/snapd/arch"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/logger"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snapenv"
+ "github.com/snapcore/snapd/systemd"
+ "github.com/snapcore/snapd/timeout"
)
type interacter interface {
@@ -231,7 +231,7 @@
SnapArch string
SnapPath string
Version string
- Revision int
+ Revision snap.Revision
Home string
}{
App: appInfo,
diff -Nru snapd-2.0.5/wrappers/services_test.go snapd-2.0.8/wrappers/services_test.go
--- snapd-2.0.5/wrappers/services_test.go 2016-05-19 13:34:50.000000000 +0000
+++ snapd-2.0.8/wrappers/services_test.go 2016-06-08 05:58:01.000000000 +0000
@@ -28,13 +28,13 @@
. "gopkg.in/check.v1"
- "github.com/ubuntu-core/snappy/dirs"
- "github.com/ubuntu-core/snappy/osutil"
- "github.com/ubuntu-core/snappy/progress"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/snap/snaptest"
- "github.com/ubuntu-core/snappy/systemd"
- "github.com/ubuntu-core/snappy/wrappers"
+ "github.com/snapcore/snapd/dirs"
+ "github.com/snapcore/snapd/osutil"
+ "github.com/snapcore/snapd/progress"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/systemd"
+ "github.com/snapcore/snapd/wrappers"
)
type servicesTestSuite struct {
@@ -66,7 +66,7 @@
return []byte("ActiveState=inactive\n"), nil
}
- info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: 12})
+ info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)})
err := wrappers.AddSnapServices(info, nil)
c.Assert(err, IsNil)
@@ -119,7 +119,7 @@
command: wat
stop-timeout: 250ms
daemon: forking
-`, &snap.SideInfo{Revision: 11})
+`, &snap.SideInfo{Revision: snap.R(11)})
err := wrappers.AddSnapServices(info, nil)
c.Assert(err, IsNil)