-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 The interface{} -> rspec.Spec conversion happens through a JSON serialization trick suggested by 梁辰晔 (Liang Chenye) [3] after the translations, because before the translations the template may contain JSON that's not represented in the OCI Spec structure (e.g. fromContainer in namespace entries). This commit still needs (marked by FIXMEs): * Lookup /proc in /proc/self/mounts (recursive?). * Compare /proc with state JSON namespace [4]. * A way to handle nested definition lists in man pages. I expect we should drop go-md2man in favor of a more established man-page format (e.g. AsciiDoc). [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]: #54 (comment) [4]: https://groups.google.com/a/opencontainers.org/forum/#!topic/dev/ujtABQoCmgk Subject: Linux: Adding the PID namespace inode to state JSON Date: Wed, 30 Dec 2015 21:34:57 -0800 Message-ID: <[email protected]> Signed-off-by: W. Trevor King <[email protected]>
- Loading branch information
Showing
4 changed files
with
159 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package translate | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"os/exec" | ||
"path/filepath" | ||
|
||
"github.com/codegangsta/cli" | ||
rspec "github.com/opencontainers/runtime-spec/specs-go" | ||
) | ||
|
||
func FromContainer(data interface{}, context *cli.Context) (translated interface{}, err error) { | ||
dataMap, ok := data.(map[string]interface{}) | ||
if !ok { | ||
return nil, fmt.Errorf("data is not a map[string]interface{}: %s", data) | ||
} | ||
|
||
linuxInterface, ok := dataMap["linux"] | ||
if !ok { | ||
return data, nil | ||
} | ||
|
||
linux, ok := linuxInterface.(map[string]interface{}) | ||
if !ok { | ||
return nil, fmt.Errorf("data.linux is not a map[string]interface{}: %s", linuxInterface) | ||
} | ||
|
||
namespacesInterface, ok := linux["namespaces"] | ||
if !ok { | ||
return data, nil | ||
} | ||
|
||
namespaces, ok := namespacesInterface.([]interface{}) | ||
if !ok { | ||
return nil, fmt.Errorf("data.linux.namespaces is not an array: %s", namespacesInterface) | ||
} | ||
|
||
for index, namespaceInterface := range namespaces { | ||
namespace, ok := namespaceInterface.(map[string]interface{}) | ||
if !ok { | ||
return nil, fmt.Errorf("data.linux.namespaces[%d] is not a map[string]interface{}: %s", index, namespaceInterface) | ||
} | ||
err := namespaceFromContainer(&namespace, index, context) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
return data, nil | ||
} | ||
|
||
func namespaceFromContainer(namespace *map[string]interface{}, index int, context *cli.Context) (err error) { | ||
fromContainerInterface, ok := (*namespace)["fromContainer"] | ||
if ok { | ||
fromContainer, ok := fromContainerInterface.(string) | ||
if !ok { | ||
return fmt.Errorf("data.linux.namespaces[%d].fromContainer is not a string: %s", index, fromContainerInterface) | ||
} | ||
delete(*namespace, "fromContainer") | ||
runtime := context.String("runtime") | ||
if (len(runtime) == 0) { | ||
return fmt.Errorf("translating fromContainer requires a non-empty --runtime") | ||
} | ||
command := exec.Command(runtime, "state", fromContainer) | ||
var out bytes.Buffer | ||
command.Stdout = &out | ||
err := command.Run() | ||
if err != nil { | ||
return err | ||
} | ||
var state rspec.State | ||
err = json.Unmarshal(out.Bytes(), &state) | ||
if err != nil { | ||
return err | ||
} | ||
namespaceTypeInterface, ok := (*namespace)["type"] | ||
if !ok { | ||
return fmt.Errorf("data.linux.namespaces[%d].type is missing: %s", index, fromContainerInterface) | ||
} | ||
namespaceType, ok := namespaceTypeInterface.(string) | ||
if !ok { | ||
return fmt.Errorf("data.linux.namespaces[%d].type is not a string: %s", index, namespaceTypeInterface) | ||
} | ||
switch namespaceType { | ||
case "network": namespaceType = "net" | ||
case "mount": namespaceType = "mnt" | ||
} | ||
proc := "/proc" // FIXME: lookup in /proc/self/mounts, check right namespace | ||
path := filepath.Join(proc, fmt.Sprint(state.Pid), "ns", namespaceType) | ||
(*namespace)["path"] = path | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
Package translate handles translation between configuration | ||
specifications. | ||
For example, it allows you to generate OCI-compliant config.json from | ||
a higher-level configuration language. | ||
*/ | ||
package translate | ||
|
||
import ( | ||
"github.com/codegangsta/cli" | ||
) | ||
|
||
// Translate maps JSON from one specification to another. | ||
type Translate func(data interface{}, context *cli.Context) (translated interface{}, err error) | ||
|
||
// Translators is a map from translator names to Translate functions. | ||
var Translators = map[string]Translate{ | ||
"fromContainer": FromContainer, | ||
} |