diff --git a/proto/Makefile b/proto/Makefile index 432899577..73295561b 100644 --- a/proto/Makefile +++ b/proto/Makefile @@ -17,7 +17,8 @@ CPP_FILES := $(CPP_SOURCE) $(CPP_HDR) DOCKER ?= docker CWD := $(shell pwd) -default: example +default: example_cpp + ./example_cpp all: go py c cpp @@ -42,6 +43,10 @@ $(CPP_DIR)/%.pb.cc: %.proto @mkdir -p $(CPP_DIR) protoc --cpp_out=$(CPP_DIR)/ $^ +%_cpp: %.cc $(CPP_FILES) + pkg-config --cflags protobuf # fails if protobuf is not installed + c++ $< $(filter %.cc, $(CPP_FILES)) -o $@ $$(pkg-config --cflags --libs protobuf) -I $(CPP_DIR) + py: $(PY_FILES) $(PY_DIR)/%_pb2.py: %.proto @@ -52,5 +57,4 @@ proto3: Dockerfile run.sh $(DOCKER) build -t $@ . && $(DOCKER) run -it -v $(CWD):/proto:ro -v $(CWD)/output:/output:rw $@ clean: - rm -rf *~ $(GO_FILES) $(C_FILES) $(PY_FILES) $(CPP_FILES) $(CWD)/output - + rm -rf *~ *_cpp $(GO_FILES) $(C_FILES) $(PY_FILES) $(CPP_FILES) $(CWD)/output diff --git a/proto/config.json b/proto/config.json new file mode 100644 index 000000000..d6ac2ba12 --- /dev/null +++ b/proto/config.json @@ -0,0 +1,35 @@ +{ + "version": "0.1.0", + "platform": { + "os": "linux", + "arch": "amd64" + }, + "process": { + "terminal": true, + "user": { + "@type": "type.googleapis.com/oci.LinuxUser", + "uid": 1, + "gid": 1, + "additionalGids": [ + 5, + 6 + ] + }, + "args": [ + "sh" + ], + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=linux" + ], + "cwd": "/root" + }, + "hostname": "mrsdalloway", + "linuxx": { + "capabilities": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ] + } +} diff --git a/proto/config.proto b/proto/config.proto index 1b1ad8018..bd128e119 100644 --- a/proto/config.proto +++ b/proto/config.proto @@ -1,30 +1,27 @@ +syntax = "proto3"; + package oci; +import "google/protobuf/any.proto"; + // Spec is the base configuration for the container. It specifies platform // independent configuration. message Spec { // Version is the version of the specification that is supported. - optional string version = 1; + string version = 1; // Platform is the host information for OS and Arch. - optional Platform platform = 2; + Platform platform = 2; // Process is the container's main process. - optional Process process = 3; + Process process = 3; // Root is the root information for the container's filesystem. - optional Root root = 4; + Root root = 4; // Hostname is the container's host name. - optional string hostname = 5; + string hostname = 5; // Mounts profile configuration for adding mounts to the container's // filesystem. repeated MountPoint mounts = 6; -} - - -// LinuxSpec is the full specification for linux containers. -message LinuxSpec { - optional Spec spec = 1; - // LinuxConfig is platform specific configuration for linux based - // containers. - optional LinuxConfig linux_config = 2; + // LinuxConfig is the Linux-specific, host-independent configuration. + LinuxConfig linuxx = 7; } // LinuxConfig contains platform specific configuration for linux based @@ -38,18 +35,18 @@ message LinuxConfig { // container is created for. message Platform { // OS is the operating system. - optional string os = 1; + string os = 1; // Arch is the architecture - optional string arch = 2; + string arch = 2; } // Process contains information to start a specific application inside the // container. message Process { // Terminal creates an interactive terminal for the container. - optional bool terminal = 1; + bool terminal = 1; // User specifies user information for the process. - optional User user = 2; + google.protobuf.Any user = 2; // Args specifies the binary and arguments for the application to // execute. repeated string args = 3; @@ -57,50 +54,35 @@ message Process { repeated string env = 4; // Cwd is the current working directory for the process and must be // relative to the container's root. - optional string cwd = 5; -} - -enum PlatformType { - UNKNOWN = 0; - LINUX = 1; -} - -// User specifies user information for the process. -message User { - // Type so that receivers of this message can `switch` for the fields - // expected - optional PlatformType type = 1; - - //optional LinuxUser linux_type = 2; - extensions 100 to 499; + string cwd = 5; } // LinuxUser specifies linux specific user and group information for the // container's main process. -extend User { +message LinuxUser { // Uid is the user id. - optional int32 uid = 101; + int32 uid = 101; // Gid is the group id. - optional int32 gid = 102; + int32 gid = 102; repeated int32 additional_gids = 103; } // Root contains information about the container's root filesystem on the host. message Root { // Path is the absolute path to the container's root filesystem. - optional string path = 1; + string path = 1; // Readonly makes the root filesystem for the container readonly before // the process is executed. - optional bool readonly = 2; + bool readonly = 2; } // MountPoint describes a directory that may be fullfilled by a mount in the // runtime.json. message MountPoint { // Name is a unique descriptive identifier for this mount point. - optional string name = 1; + string name = 1; // Path specifies the path of the mount. The path and child directories // MUST exist, a runtime MUST NOT create directories automatically to a // mount point. - optional string path = 2; + string path = 2; } diff --git a/proto/example.cc b/proto/example.cc new file mode 100644 index 000000000..f1ee84d03 --- /dev/null +++ b/proto/example.cc @@ -0,0 +1,104 @@ +// See README.txt for information and build instructions. + +#include +#include +#include + +#include +#include +#include +#include + +#include "config.pb.h" +#include "runtime_config.pb.h" + +using namespace std; + +static const char kTypeUrlPrefix[] = "type.googleapis.com"; + +static string GetTypeUrl(const google::protobuf::Descriptor* message) { + return string(kTypeUrlPrefix) + "/" + message->full_name(); +} + +static bool ReadMessage(string path, google::protobuf::Message *message) { + string binary; + ifstream input(path.c_str(), ios::in | ios::binary); + if (!input) { + cout << path << ": File not found." << endl; + return false; + } + string json( (istreambuf_iterator(input)), + istreambuf_iterator() ); + google::protobuf::scoped_ptr resolver; + resolver.reset(google::protobuf::util::NewTypeResolverForDescriptorPool( + kTypeUrlPrefix, + google::protobuf::DescriptorPool::generated_pool())); + GOOGLE_CHECK_OK(google::protobuf::util::JsonToBinaryString( + resolver.get(), + GetTypeUrl(message->GetDescriptor()), + json, + &binary)); + return message->ParseFromString(binary); +} + +static bool WriteMessage(const google::protobuf::Message& message) { + string json; + google::protobuf::util::JsonOptions options; + google::protobuf::scoped_ptr resolver; + resolver.reset(google::protobuf::util::NewTypeResolverForDescriptorPool( + kTypeUrlPrefix, + google::protobuf::DescriptorPool::generated_pool())); + options.add_whitespace = true; + GOOGLE_CHECK_OK(google::protobuf::util::BinaryToJsonString( + resolver.get(), + GetTypeUrl(message.GetDescriptor()), + message.SerializeAsString(), + &json, + options)); + cout << json; + return true; +} + +// Main function: Reads the config from a file and writes it to stdout. +int main(int argc, char* argv[]) { + // Verify that the version of the library that we linked against is + // compatible with the version of the headers we compiled against. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + oci::Spec config; + oci::RuntimeSpec runtime; + + if (!ReadMessage("config.json", &config)) { + cerr << "config.json: Failed to load." << endl; + return -1; + } + +/* + oci::LinuxUser user; + user.set_uid(1); + user.set_gid(1); + user.add_additional_gids(5); + user.add_additional_gids(6); + config.mutable_process()->mutable_user()->PackFrom(user); +*/ + + if (!WriteMessage(config)) { + cerr << "config.json: Failed to write to stdout." << endl; + return -1; + } + + if (!ReadMessage("runtime.json", &runtime)) { + cerr << "runtime.json: Failed to load." << endl; + return -1; + } + + if (!WriteMessage(runtime)) { + cerr << "runtime.json: Failed to write to stdout." << endl; + return -1; + } + + // Optional: Delete all global objects allocated by libprotobuf. + google::protobuf::ShutdownProtobufLibrary(); + + return 0; +} diff --git a/proto/runtime.json b/proto/runtime.json new file mode 100644 index 000000000..8ffc608c4 --- /dev/null +++ b/proto/runtime.json @@ -0,0 +1,220 @@ +{ + "mounts": { + "proc": { + "type": "proc", + "source": "proc", + "options": [] + }, + "dev": { + "type": "tmpfs", + "source": "tmpfs", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ] + }, + "devpts": { + "type": "devpts", + "source": "devpts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ] + }, + "data": { + "type": "bind", + "source": "/volumes/testing", + "options": [ + "rbind", + "rw" + ] + } + }, + "hooks": { + "prestart": [ + { + "path": "/usr/bin/fix-mounts", + "args": [ + "arg1", + "arg2" + ], + "env": [ + "key1=value1" + ] + }, + { + "path": "/usr/bin/setup-network" + } + ], + "poststop": [ + { + "path": "/usr/sbin/cleanup.sh", + "args": [ + "-f" + ] + } + ] + }, + "linuxx": { + "uidMappings": [ + { + "hostID": 1000, + "containerID": 0, + "size": 10 + } + ], + "gidMappings": [ + { + "hostID": 1000, + "containerID": 0, + "size": 10 + } + ], + "rlimits": [ + { + "type": "RLIMIT_NPROC", + "soft": 1024, + "hard": 102400 + } + ], + "sysctl": { + "net.ipv4.ip_forward": "1", + "net.core.somaxconn": "256" + }, + "resources": { + "disableOOMKiller": false, + "memory": { + "limit": 0, + "reservation": 0, + "swap": 0, + "kernel": 0, + "swappiness": -1 + }, + "cpu": { + "shares": 0, + "quota": 0, + "period": 0, + "realtimeRuntime": 0, + "realtimePeriod": 0, + "cpus": "", + "mems": "" + }, + "blockIO": { + "blkioWeight": 0, + "blkioWeightDevice": "", + "blkioThrottleReadBpsDevice": "", + "blkioThrottleWriteBpsDevice": "", + "blkioThrottleReadIopsDevice": "", + "blkioThrottleWriteIopsDevice": "" + }, + "hugepageLimits": null, + "network": { + "classId": "", + "priorities": null + } + }, + "cgroupsPath": "/myRuntime/myContainer", + "namespaces": [ + { + "type": "pid", + "path": "/proc/1234/ns/pid" + }, + { + "type": "network", + "path": "/var/run/netns/neta" + }, + { + "type": "mount" + }, + { + "type": "ipc" + }, + { + "type": "uts" + }, + { + "type": "user" + } + ], + "devices": [ + { + "path": "/dev/random", + "type": "c", + "major": 1, + "minor": 8, + "permissions": "rwm", + "fileMode": 666, + "uid": 0, + "gid": 0 + }, + { + "path": "/dev/urandom", + "type": "c", + "major": 1, + "minor": 9, + "permissions": "rwm", + "fileMode": 666, + "uid": 0, + "gid": 0 + }, + { + "path": "/dev/null", + "type": "c", + "major": 1, + "minor": 3, + "permissions": "rwm", + "fileMode": 666, + "uid": 0, + "gid": 0 + }, + { + "path": "/dev/zero", + "type": "c", + "major": 1, + "minor": 5, + "permissions": "rwm", + "fileMode": 666, + "uid": 0, + "gid": 0 + }, + { + "path": "/dev/tty", + "type": "c", + "major": 5, + "minor": 0, + "permissions": "rwm", + "fileMode": 666, + "uid": 0, + "gid": 0 + }, + { + "path": "/dev/full", + "type": "c", + "major": 1, + "minor": 7, + "permissions": "rwm", + "fileMode": 666, + "uid": 0, + "gid": 0 + } + ], + "apparmorProfile": "acme_secure_profile", + "selinuxProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c124,c675", + "seccomp": { + "defaultAction": "SCMP_ACT_ALLOW", + "syscalls": [ + { + "name": "getcwd", + "action": "SCMP_ACT_ERRNO" + } + ] + }, + "rootfsPropagation": "slave" + } +} diff --git a/proto/runtime_config.proto b/proto/runtime_config.proto index 4f1db2eae..85700f23e 100644 --- a/proto/runtime_config.proto +++ b/proto/runtime_config.proto @@ -1,3 +1,5 @@ +syntax = "proto3"; + package oci; // RuntimeSpec is the generic runtime state information on a running container @@ -7,29 +9,31 @@ message RuntimeSpec { // in Spec. repeated MountFieldEntry mounts = 1; // Hooks are the commands run at various lifecycle events of the container. - optional Hooks hooks = 2; + Hooks hooks = 2; + // LinuxRuntime is the Linux-specific, host-specific configuration. + LinuxRuntime linuxx = 3; } // MountFieldEntry is more backwards compatible protobuf associative map (than map) message MountFieldEntry { - required string key = 1; - required Mount value = 2; + string key = 1; + Mount value = 2; } // Mount specifies a mount for a container message Mount { // Type specifies the mount kind. - optional string type = 1; + string type = 1; // Source specifies the source path of the mount. In the case of bind mounts on // linux based systems this would be the file on the host. - optional string source = 2; + string source = 2; // Options are fstab style mount options. repeated string options = 3; } // Hook specifies a command that is run at a particular event in the lifecycle of a container message Hook { - optional string path = 1; + string path = 1; repeated string args = 2; repeated string env = 3; } @@ -43,162 +47,149 @@ message Hooks { repeated Hook poststop = 2; } -// LinuxStateDirectory holds the container's state information -message DefaultState { - // TODO(vbatts) not as elegant in some ways, but there is not a concept of const here - optional string directory = 1 [default = "/run/opencontainer/containers"]; -} - /* BEGIN Linux specific runtime */ -// LinuxRuntimeSpec is the full specification for linux containers. -message LinuxRuntimeSpec { - optional RuntimeSpec runtime_spec = 1; - // LinuxRuntime is platform specific configuration for linux based containers. - optional LinuxRuntime linux = 2; -} - // LinuxRuntime hosts the Linux-only runtime information message LinuxRuntime { // UidMapping specifies user mappings for supporting user namespaces on linux. - repeated IDMapping uid_mapping = 1; + repeated IDMapping uidMappings = 1; // GidMapping specifies group mappings for supporting user namespaces on linux. - repeated IDMapping gid_mapping = 2; + repeated IDMapping gidMappings = 2; // Rlimits specifies rlimit options to apply to the container's process. repeated Rlimit rlimits = 3; // Sysctl are a set of key value pairs that are set for the container on start repeated StringStringEntry sysctl = 4; // Resources contain cgroup information for handling resource constraints // for the container - optional Resources resources = 5; + Resources resources = 5; // CgroupsPath specifies the path to cgroups that are created and/or joined by the container. // The path is expected to be relative to the cgroups mountpoint. // If resources are specified, the cgroups at CgroupsPath will be updated based on resources. - optional string cgroups_path = 6; + string cgroupsPath = 6; // Namespaces contains the namespaces that are created and/or joined by the container repeated Namespace namespaces = 7; // Devices are a list of device nodes that are created and enabled for the container repeated Device devices = 8; // ApparmorProfile specified the apparmor profile for the container. - optional string apparmor_profile = 9; + string apparmorProfile = 9; // SelinuxProcessLabel specifies the selinux context that the container process is run as. - optional string selinux_process_label = 10; + string selinuxProcessLabel = 10; // Seccomp specifies the seccomp security settings for the container. - optional Seccomp seccomp = 11; + Seccomp seccomp = 11; // RootfsPropagation is the rootfs mount propagation mode for the container - optional string rootfs_propagation = 12; + string rootfsPropagation = 12; } // IDMapping specifies UID/GID mappings message IDMapping { // HostID is the UID/GID of the host user or group - optional int32 host_id = 1; + int32 hostID = 1; // ContainerID is the UID/GID of the container's user or group - optional int32 container_id = 2; + int32 containerID = 2; // Size is the length of the range of IDs mapped between the two namespaces - optional int32 size = 3; + int32 size = 3; } // Rlimit type and restrictions message Rlimit { // Type of the rlimit to set - optional string type = 1; + string type = 1; // Hard is the hard limit for the specified type - optional uint64 hard = 2; + uint64 hard = 2; // Soft is the soft limit for the specified type - optional uint64 soft = 3; + uint64 soft = 3; } // StringStringEntry is more backwards compatible protobuf associative map (than map) message StringStringEntry { - required string key = 1; - required string value = 2; + string key = 1; + string value = 2; } // Resources has container runtime resource constraints message Resources { // DisableOOMKiller disables the OOM killer for out of memory conditions - optional bool disable_oom_killer = 1; + bool disableOomKiller = 1; // Memory restriction configuration - optional Memory memory = 2; + Memory memory = 2; // CPU resource restriction configuration - optional CPU cpu = 3; + CPU cpu = 3; // Task resource restriction configuration. - optional Pids pids = 4; + Pids pids = 4; // BlockIO restriction configuration - optional BlockIO block_io = 5; + BlockIO blockIO = 5; // Hugetlb limit (in bytes) - repeated HugepageLimit hugepage_limits = 6; + repeated HugepageLimit hugepageLimits = 6; // Network restriction configuration - optional Network network = 7; + Network network = 7; } // Memory for Linux cgroup 'memory' resource management message Memory { // Memory limit (in bytes) - optional int64 limit = 1; + int64 limit = 1; // Memory reservation or soft_limit (in bytes) - optional int64 reservation = 2; + int64 reservation = 2; // Total memory usage (memory + swap); set `-1' to disable swap - optional int64 swap = 3; + int64 swap = 3; // Kernel memory limit (in bytes) - optional int64 kernel = 4; + int64 kernel = 4; // How aggressive the kernel will swap memory pages. Range from 0 to 100. Set -1 to use system default - optional int64 Swappiness = 5; + int64 Swappiness = 5; } // CPU for Linux cgroup 'cpu' resource management message CPU { // CPU shares (relative weight vs. other cgroups with cpu shares) - optional int64 shares = 1; + int64 shares = 1; // CPU hardcap limit (in usecs). Allowed cpu time in a given period - optional int64 quota = 2; + int64 quota = 2; // CPU period to be used for hardcapping (in usecs). 0 to use system default - optional int64 period = 3; + int64 period = 3; // How many time CPU will use in realtime scheduling (in usecs) - optional int64 realtime_runtime = 4; + int64 realtimeRuntime = 4; // CPU period to be used for realtime scheduling (in usecs) - optional int64 realtime_period = 5; + int64 realtimePeriod = 5; // CPU to use within the cpuset - optional string cpus = 6; + string cpus = 6; // MEM to use within the cpuset - optional string mems = 7; + string mems = 7; } // Pids for Linux cgroup 'pids' resource management (Linux 4.3) message Pids { // Maximum number of PIDs. A value < 0 implies "no limit". - optional int64 limit = 1; + int64 limit = 1; } // BlockIO for Linux cgroup 'blockio' resource management message BlockIO { // Specifies per cgroup weight, range is from 10 to 1000 - optional int64 weight = 1; + int64 weight = 1; // Weight per cgroup per device, can override BlkioWeight - optional string weight_device = 2; + string weightDevice = 2; // IO read rate limit per cgroup per device, bytes per second - optional string throttle_read_bps_device = 3; + string throttleReadBpsDevice = 3; // IO write rate limit per cgroup per divice, bytes per second - optional string throttle_write_bps_device = 4; + string throttleWriteBpsDevice = 4; // IO read rate limit per cgroup per device, IO per second - optional string throttle_read_iops_device = 5; + string throttleReadIopsDevice = 5; // IO write rate limit per cgroup per device, IO per second - optional string throttle_write_iops_device = 6; + string throttleWriteIopsDevice = 6; } // HugepageLimit structure corresponds to limiting kernel hugepages message HugepageLimit { - optional string pagesize = 1; - optional int32 limit = 2; + string pagesize = 1; + int32 limit = 2; } // Network identification and priority configuration message Network { // Set class identifier for container's network packets - optional string class_id = 1; + string classId = 1; // Set priority of network traffic for container repeated InterfacePriority priorities = 2; } @@ -206,63 +197,63 @@ message Network { // InterfacePriority for network interfaces message InterfacePriority { // Name is the name of the network interface - optional string name = 1; + string name = 1; // Priority for the interface - optional int64 priority = 2; + int64 priority = 2; } // Namespace is the configuration for a linux namespace message Namespace { // Type is the type of Linux namespace - optional string type = 1; + string type = 1; // Path is a path to an existing namespace persisted on disk that can be joined // and is of the same type - optional string path = 2; + string path = 2; } // Device represents the information on a Linux special device file message Device { // Path to the device. - optional string path = 1; + string path = 1; // Device type, block, char, etc. // TODO(vbatts) ensure int32 is fine here, instead of golang's rune - optional int32 type = 2; + int32 type = 2; // Major is the device's major number. - optional int64 major = 3; + int64 major = 3; // Minor is the device's minor number. - optional int64 minor = 4; + int64 minor = 4; // Cgroup permissions format, rwm. - optional string permissions = 5; + string permissions = 5; // FileMode permission bits for the device. // TODO(vbatts) os.FileMode is an octal uint32 - optional uint32 file_mode = 6; + uint32 fileMode = 6; // Uid of the device. - optional uint32 uid = 7; + uint32 uid = 7; // Gid of the device. - optional uint32 gid = 8; + uint32 gid = 8; } // Seccomp represents syscall restrictions message Seccomp { // TODO(vbatts) string instead of "Action" type - optional string default_action = 1; + string defaultAction = 1; repeated Syscall syscalls = 2; } // Syscall is used to match a syscall in Seccomp message Syscall { - optional string name = 1; - optional string action = 2; + string name = 1; + string action = 2; repeated Arg args = 3; } // Arg used for matching specific syscall arguments in Seccomp message Arg { - optional uint32 index = 1; - optional uint64 value = 2; - optional uint64 value_two = 3; + uint32 index = 1; + uint64 value = 2; + uint64 value_two = 3; // Op is the operator string - optional string op = 4; + string op = 4; } /*