-
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.
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). The /proc lookup could still be improved: * Lookup the mount path (currently hard-coded to /proc) in /proc/self/mounts. This would extend support to users who had mounted proc at a different location, but it's hard to find self/mounts unless you already know where proc is mounted ;). * Compare /proc with the state JSON's implied PID namespace [4]. This would extend support to users in a different PID namespace than the one in which the state JSON's 'pid' entry applied. But those are likely to be corner cases (and until something like [4] lands, the latter is not possible). So I'm punting them into the future, where they can be fixed as we discover methods to fix them. [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
165 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, | ||
} |