Skip to content

Commit 215cee9

Browse files
committed
WIP: translate: Stub in a translation framework
Add tooling to translate higher-level configs into the basic OCI config. On IRC, Julz floated a linux.namespaces[].fromContainer as a higher-level version of linux.namespaces[].path for emulating exec [1]. That makes sense to me, and Mrunal is open to something like [2]: $ ocitools generate --template=high-level-config.json --translate=fromContainer --runtime=runc This commit still needs: * The state JSON lookup and path logic from [3]. * A way to convert the interface{} to an rspec.Spec (the current FIXME raises: FATA[0000] translated template has an invalid schema). [1]: http://ircbot.wl.linuxfoundation.org/eavesdrop/%23opencontainers/%23opencontainers.2016-04-27.log.html#t2016-04-27T20:32:09 [2]: http://ircbot.wl.linuxfoundation.org/eavesdrop/%23opencontainers/%23opencontainers.2016-04-28.log.html#t2016-04-28T16:12:48 [3]: opencontainers/runtime-spec#391 Signed-off-by: W. Trevor King <[email protected]>
1 parent 8ab86b6 commit 215cee9

3 files changed

Lines changed: 92 additions & 5 deletions

File tree

generate.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/codegangsta/cli"
1414
rspec "github.com/opencontainers/runtime-spec/specs-go"
1515
"github.com/syndtr/gocapability/capability"
16+
"github.com/opencontainers/ocitools/translate"
1617
)
1718

1819
var generateFlags = []cli.Flag{
@@ -55,6 +56,7 @@ var generateFlags = []cli.Flag{
5556
cli.StringSliceFlag{Name: "seccomp-syscalls", Usage: "specifies Additional architectures permitted to be used for system calls, e.g Name:Action:Arg1_index/Arg1_value/Arg1_valuetwo/Arg1_op, Arg2_index/Arg2_value/Arg2_valuetwo/Arg2_op "},
5657
cli.StringSliceFlag{Name: "seccomp-allow", Usage: "specifies syscalls to be added to allowed"},
5758
cli.StringFlag{Name: "template", Usage: "base template to use for creating the configuration"},
59+
cli.StringSliceFlag{Name: "translate", Usage: "translate higher level constructs"},
5860
cli.StringSliceFlag{Name: "label", Usage: "add annotations to the configuration e.g. key=value"},
5961
}
6062

@@ -92,12 +94,29 @@ var generateCommand = cli.Command{
9294
}
9395
}
9496

95-
err := modify(spec, context)
97+
translations := context.StringSlice("translate")
98+
for _, translation := range translations {
99+
translator, ok := translate.Translators[translation]
100+
if !ok {
101+
logrus.Fatalf("unrecognized translation: %s", translation)
102+
}
103+
var err error
104+
spec, err = translator(spec)
105+
if err != nil {
106+
logrus.Fatal(err)
107+
}
108+
}
109+
110+
strictSpec, ok := spec.(rspec.Spec) // FIXME: assert struct type?
111+
if !ok {
112+
logrus.Fatal("translated template has an invalid schema")
113+
}
114+
err := modify(&strictSpec, context)
96115
if err != nil {
97116
logrus.Fatal(err)
98117
}
99118
cName := "config.json"
100-
data, err := json.MarshalIndent(&spec, "", "\t")
119+
data, err := json.MarshalIndent(&strictSpec, "", "\t")
101120
if err != nil {
102121
logrus.Fatal(err)
103122
}
@@ -107,7 +126,7 @@ var generateCommand = cli.Command{
107126
},
108127
}
109128

110-
func loadTemplate(path string) (spec *rspec.Spec, err error) {
129+
func loadTemplate(path string) (spec interface{}, err error) {
111130
cf, err := os.Open(path)
112131
if err != nil {
113132
if os.IsNotExist(err) {
@@ -675,7 +694,7 @@ func setupNamespaces(spec *rspec.Spec, context *cli.Context) {
675694

676695
func sPtr(s string) *string { return &s }
677696

678-
func getDefaultTemplate() *rspec.Spec {
697+
func getDefaultTemplate() interface{} {
679698
spec := rspec.Spec{
680699
Version: rspec.Version,
681700
Platform: rspec.Platform{
@@ -790,5 +809,5 @@ func getDefaultTemplate() *rspec.Spec {
790809
},
791810
}
792811

793-
return &spec
812+
return spec
794813
}

translate/from_container.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package translate
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func init() {
8+
Translators["fromContainer"] = FromContainer
9+
}
10+
11+
func FromContainer(data interface{}) (translated interface{}, err error) {
12+
dataMap, ok := data.(map[string]interface{})
13+
if !ok {
14+
return nil, fmt.Errorf("data is not a map[string]interface{}: %s", data)
15+
}
16+
17+
linuxInterface, ok := dataMap["linux"]
18+
if !ok {
19+
return data, nil
20+
}
21+
22+
linux, ok := linuxInterface.(map[string]interface{})
23+
if !ok {
24+
return nil, fmt.Errorf("data.linux is not a map[string]interface{}: %s", linuxInterface)
25+
}
26+
27+
namespacesInterface, ok := linux["namespaces"]
28+
if !ok {
29+
return data, nil
30+
}
31+
32+
namespaces, ok := namespacesInterface.([]interface{})
33+
if !ok {
34+
return nil, fmt.Errorf("data.linux.namespaces is not an array: %s", namespacesInterface)
35+
}
36+
37+
for i, namespaceInterface := range namespaces {
38+
namespace, ok := namespaceInterface.(map[string]interface{})
39+
if !ok {
40+
return nil, fmt.Errorf("data.linux.namespaces[%d] is not a map[string]interface{}: %s", i, namespaceInterface)
41+
}
42+
fromContainerInterface, ok := namespace["fromContainer"]
43+
if ok {
44+
fromContainer, ok := fromContainerInterface.(string)
45+
if !ok {
46+
return nil, fmt.Errorf("data.linux.namespaces[%d].fromContainer is not a string: %s", i, fromContainerInterface)
47+
}
48+
delete(namespace, "fromContainer")
49+
namespace["path"] = fromContainer
50+
}
51+
}
52+
53+
return data, nil
54+
}

translate/translate.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
Package translate handles translation between configuration
3+
specifications.
4+
5+
For example, it allows you to generate OCI-compliant config.json from
6+
a higher-level configuration language.
7+
*/
8+
package translate
9+
10+
// Translate maps JSON from one specification to another.
11+
type Translate func(data interface{}) (translated interface{}, err error)
12+
13+
// Translators is a map from translator names to Translate functions.
14+
var Translators = map[string]Translate{}

0 commit comments

Comments
 (0)