rkt: turn rkt/app.go into the package common/apps

Step towards supplying stage0 with Apps rather than a bunch of
lists...
This commit is contained in:
Vito Caputo
2015-03-26 13:35:52 -07:00
parent 59e34f4feb
commit 67158a4e7f
6 changed files with 140 additions and 124 deletions
+102
View File
@@ -0,0 +1,102 @@
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//+build linux
package apps
import (
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
)
type App struct {
Image string // the image reference as supplied by the user on the cli
Args []string // any arguments the user supplied for this app
Asc string // signature file override for image verification (if fetching occurs)
// TODO(jonboulle): These images are partially-populated hashes, this should be clarified.
ImageID types.Hash // resolved image identifier
}
type Apps struct {
apps []App
}
// Reset creates a new slice for al.apps, needed by tests
func (al *Apps) Reset() {
al.apps = make([]App, 0)
}
// Count returns the number of apps in al
func (al *Apps) Count() int {
return len(al.apps)
}
// Create creates a new app in al and returns a pointer to it
func (al *Apps) Create(img string) {
al.apps = append(al.apps, App{Image: img})
}
// Last returns a pointer to the top app in al
func (al *Apps) Last() *App {
if len(al.apps) == 0 {
return nil
}
return &al.apps[len(al.apps)-1]
}
// Walk iterates on al.apps calling f for each app
// walking stops if f returns an error, the error is simply returned
func (al *Apps) Walk(f func(*App) error) error {
for i, _ := range al.apps {
// XXX(vc): note we supply f() with a pointer to the app instance in al.apps to enable modification by f()
if err := f(&al.apps[i]); err != nil {
return err
}
}
return nil
}
// these convenience functions just return typed lists containing just the named member
// TODO(vc): these probably go away when we just pass Apps to stage0
// GetImages returns a list of the images in al, one per app.
// The order reflects the app order in al.
func (al *Apps) GetImages() []string {
il := []string{}
for _, a := range al.apps {
il = append(il, a.Image)
}
return il
}
// GetArgs returns a list of lists of arguments in al, one list of args per app.
// The order reflects the app order in al.
func (al *Apps) GetArgs() [][]string {
aal := [][]string{}
for _, a := range al.apps {
aal = append(aal, a.Args)
}
return aal
}
// GetImageIDs returns a list of the imageIDs in al, one per app.
// The order reflects the app order in al.
func (al *Apps) GetImageIDs() []types.Hash {
hl := []types.Hash{}
for _, a := range al.apps {
hl = append(hl, a.ImageID)
}
return hl
}
+16 -103
View File
@@ -20,71 +20,18 @@ import (
"flag"
"fmt"
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
"github.com/coreos/rkt/common/apps"
)
var (
Apps rktApps // global apps
rktApps apps.Apps // global used by run/prepare for representing the apps expressed via the cli
)
type rktApp struct {
image string // the image reference as supplied by the user on the cli
args []string // any arguments the user supplied for this app
asc string // signature file override for image verification (if fetching occurs)
imageID types.Hash // resolved image identifier
}
// this needs to be a struct for the type defines like appAsc to work correctly with receivers
type rktApps struct {
apps []rktApp
}
// reset creates a new slice for al.apps, needed by tests
func (al *rktApps) reset() {
al.apps = make([]rktApp, 0)
}
// count returns the number of apps in al
func (al *rktApps) count() int {
return len(al.apps)
}
// create creates a new app in al and returns a pointer to it
func (al *rktApps) create(img string) {
al.apps = append(al.apps, rktApp{image: img})
}
// last returns a pointer to the top app in al
func (al *rktApps) last() *rktApp {
if len(al.apps) == 0 {
return nil
} else {
return &al.apps[len(al.apps)-1]
}
}
// appendArg appends another argument onto the app
func (a *rktApp) appendArg(arg string) {
a.args = append(a.args, arg)
}
// sets the ascii-armored signature file path for the app
func (a *rktApp) setAsc(asc string) {
a.asc = asc
}
// gets the ascii-armored signature file path for the app
func (a *rktApp) getAsc() string {
return a.asc
}
// parseApps looks through the args for support of per-app argument lists delimited with "--" and "---".
// Between per-app argument lists flags.Parse() is called using the supplied FlagSet.
// Anything not consumed by flags.Parse() and not found to be a per-app argument list is treated as an image.
func (al *rktApps) parse(args []string, flags *flag.FlagSet) error {
al.reset()
nAppsLastAppArgs := al.count()
func parseApps(al *apps.Apps, args []string, flags *flag.FlagSet) error {
nAppsLastAppArgs := al.Count()
// valid args here may either be:
// not-"--"; flags handled by *flags or an image specifier
@@ -101,7 +48,8 @@ func (al *rktApps) parse(args []string, flags *flag.FlagSet) error {
inAppArgs = false
default:
// keep appending to this app's args
al.last().appendArg(a)
app := al.Last()
app.Args = append(app.Args, a)
}
} else {
switch a {
@@ -110,13 +58,13 @@ func (al *rktApps) parse(args []string, flags *flag.FlagSet) error {
inAppArgs = true
// catch some likely mistakes
if nAppsLastAppArgs == al.count() {
if al.count() == 0 {
if nAppsLastAppArgs == al.Count() {
if al.Count() == 0 {
return fmt.Errorf("an image is required before any app arguments")
}
return fmt.Errorf("only one set of app arguments allowed per image")
}
nAppsLastAppArgs = al.count()
nAppsLastAppArgs = al.Count()
case "---":
// ignore triple dashes since they aren't images
// TODO(vc): I don't think ignoring this is appropriate, probably should error; it implies malformed argv.
@@ -139,7 +87,7 @@ func (al *rktApps) parse(args []string, flags *flag.FlagSet) error {
i += nInterFlags - 1 // - 1 because of i++
} else {
// flags.Parse() didn't want this arg, treat as image
al.create(a)
al.Create(a)
}
}
}
@@ -148,65 +96,30 @@ func (al *rktApps) parse(args []string, flags *flag.FlagSet) error {
return nil
}
// these convenience functions just return typed lists containing just the named member
// TODO(vc): these probably go away when we just pass rktApps to stage0
// getImages returns a list of the images in al, one per app.
// The order reflects the app order in al.
func (al *rktApps) getImages() []string {
il := []string{}
for _, a := range al.apps {
il = append(il, a.image)
}
return il
}
// getArgs returns a list of lists of arguments in al, one list of args per app.
// The order reflects the app order in al.
func (al *rktApps) getArgs() [][]string {
aal := [][]string{}
for _, a := range al.apps {
aal = append(aal, a.args)
}
return aal
}
// getImageIDs returns a list of the imageIDs in al, one per app.
// The order reflects the app order in al.
func (al *rktApps) getImageIDs() []types.Hash {
hl := []types.Hash{}
for _, a := range al.apps {
hl = append(hl, a.imageID)
}
return hl
}
// Value interface implementations for the various per-app fields we provide flags for
// appAsc is for aci --signature overrides
type appAsc rktApps
type appAsc apps.Apps
func (al *appAsc) Set(s string) error {
app := (*rktApps)(al).last()
app := (*apps.Apps)(al).Last()
if app == nil {
return fmt.Errorf("--signature must follow an image")
}
if app.getAsc() != "" {
if app.Asc != "" {
return fmt.Errorf("--signature specified multiple times for the same image")
}
app.setAsc(s)
app.Asc = s
return nil
}
func (al *appAsc) String() string {
app := (*rktApps)(al).last()
app := (*apps.Apps)(al).Last()
if app == nil {
return ""
}
return app.getAsc()
return app.Asc
}
// TODO(vc): --mount, --set-env, etc.
+4 -3
View File
@@ -62,9 +62,10 @@ func TestParseAppArgs(t *testing.T) {
}
for i, tt := range tests {
err := Apps.parse(strings.Split(tt.in, " "), flags)
ga := Apps.getArgs()
gi := Apps.getImages()
rktApps.Reset()
err := parseApps(&rktApps, strings.Split(tt.in, " "), flags)
ga := rktApps.GetArgs()
gi := rktApps.GetImages()
if gerr := (err != nil); gerr != tt.werr {
t.Errorf("#%d: err==%v, want errstate %t", i, err, tt.werr)
}
+7 -7
View File
@@ -21,20 +21,20 @@ import (
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
"github.com/coreos/rkt/cas"
"github.com/coreos/rkt/common/apps"
"github.com/coreos/rkt/pkg/keystore"
)
// findImages uses findImage to attain a list of image hashes using discovery if necessary
func (al *rktApps) findImages(ds *cas.Store, ks *keystore.Keystore) error {
for _, app := range al.apps {
h, err := findImage(app.image, app.asc, ds, ks, true)
func findImages(al *apps.Apps, ds *cas.Store, ks *keystore.Keystore) error {
return al.Walk(func(app *apps.App) error {
h, err := findImage(app.Image, app.Asc, ds, ks, true)
if err != nil {
return err
}
app.imageID = *h
}
return nil
app.ImageID = *h
return nil
})
}
// findImage will recognize a ACI hash and use that, import a local file, use
+5 -5
View File
@@ -67,12 +67,12 @@ func runPrepare(args []string) (exit int) {
}
}
if err = Apps.parse(args, &prepareFlags); err != nil {
if err = parseApps(&rktApps, args, &prepareFlags); err != nil {
stderr("prepare: error parsing app image arguments: %v", err)
return 1
}
if Apps.count() < 1 {
if rktApps.Count() < 1 {
stderr("prepare: Must provide at least one image")
return 1
}
@@ -97,7 +97,7 @@ func runPrepare(args []string) (exit int) {
return 1
}
if err := Apps.findImages(ds, getKeystore()); err != nil {
if err := findImages(&rktApps, ds, getKeystore()); err != nil {
stderr("%v", err)
return 1
}
@@ -114,9 +114,9 @@ func runPrepare(args []string) (exit int) {
Debug: globalFlags.Debug,
Stage1Image: *s1img,
UUID: p.uuid,
Images: Apps.getImageIDs(),
Images: rktApps.GetImageIDs(),
},
ExecAppends: Apps.getArgs(),
ExecAppends: rktApps.GetArgs(),
Volumes: []types.Volume(flagVolumes),
InheritEnv: flagInheritEnv,
ExplicitEnv: flagExplicitEnv.Strings(),
+6 -6
View File
@@ -78,7 +78,7 @@ func init() {
runFlags.BoolVar(&flagNoOverlay, "no-overlay", false, "disable overlay filesystem")
runFlags.Var(&flagExplicitEnv, "set-env", "an environment variable to set for apps in the form name=value")
runFlags.BoolVar(&flagInteractive, "interactive", false, "run pod interactively")
runFlags.Var((*appAsc)(&Apps), "signature", "local signature file to use in validating the preceding image")
runFlags.Var((*appAsc)(&rktApps), "signature", "local signature file to use in validating the preceding image")
flagVolumes = volumeList{}
}
@@ -97,13 +97,13 @@ func runRun(args []string) (exit int) {
}
}
err := Apps.parse(args, &runFlags)
err := parseApps(&rktApps, args, &runFlags)
if err != nil {
stderr("run: error parsing app image arguments: %v", err)
return 1
}
if Apps.count() < 1 {
if rktApps.Count() < 1 {
stderr("run: must provide at least one image")
return 1
}
@@ -120,7 +120,7 @@ func runRun(args []string) (exit int) {
return 1
}
if err := Apps.findImages(ds, getKeystore()); err != nil {
if err := findImages(&rktApps, ds, getKeystore()); err != nil {
stderr("%v", err)
return 1
}
@@ -135,13 +135,13 @@ func runRun(args []string) (exit int) {
Store: ds,
Stage1Image: *s1img,
UUID: p.uuid,
Images: Apps.getImageIDs(),
Images: rktApps.GetImageIDs(),
Debug: globalFlags.Debug,
}
pcfg := stage0.PrepareConfig{
CommonConfig: cfg,
ExecAppends: Apps.getArgs(),
ExecAppends: rktApps.GetArgs(),
Volumes: []types.Volume(flagVolumes),
InheritEnv: flagInheritEnv,
ExplicitEnv: flagExplicitEnv.Strings(),