From 52e0dc7271641c698860ccaa9a80f133f0b512d4 Mon Sep 17 00:00:00 2001 From: xuxuepeng Date: Tue, 11 Jul 2023 17:26:55 +0800 Subject: [PATCH 1/2] Add sandbox protobuf files Signed-off-by: xuxuepeng --- cmake/protoc.cmake | 15 ++ .../containerd/api/types/mount.proto | 43 ++++ .../containerd/api/types/platform.proto | 29 +++ .../containerd/api/types/sandbox.proto | 53 +++++ .../sandbox/google/protobuf/any.proto | 155 +++++++++++++ .../sandbox/google/protobuf/empty.proto | 52 +++++ .../sandbox/google/protobuf/timestamp.proto | 138 ++++++++++++ .../sandbox/google/protobuf/wrappers.proto | 123 ++++++++++ src/api/services/sandbox/sandbox.proto | 210 ++++++++++++++++++ 9 files changed, 818 insertions(+) create mode 100644 src/api/services/sandbox/github.com/containerd/containerd/api/types/mount.proto create mode 100644 src/api/services/sandbox/github.com/containerd/containerd/api/types/platform.proto create mode 100644 src/api/services/sandbox/github.com/containerd/containerd/api/types/sandbox.proto create mode 100644 src/api/services/sandbox/google/protobuf/any.proto create mode 100644 src/api/services/sandbox/google/protobuf/empty.proto create mode 100644 src/api/services/sandbox/google/protobuf/timestamp.proto create mode 100644 src/api/services/sandbox/google/protobuf/wrappers.proto create mode 100644 src/api/services/sandbox/sandbox.proto diff --git a/cmake/protoc.cmake b/cmake/protoc.cmake index 1491e17d7..9172fe494 100644 --- a/cmake/protoc.cmake +++ b/cmake/protoc.cmake @@ -12,6 +12,10 @@ if (ENABLE_NATIVE_NETWORK) set(NETWORK_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/network) endif() +if (ENABLE_CRI_API_V1 AND ENABLE_SANDBOXER) +set(SANDBOX_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/sandbox) +endif() + macro(PROTOC_CPP_GEN proto_name cpp_out_path proto_path) execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/${proto_name} --cpp_out=${cpp_out_path} ${proto_path} ERROR_VARIABLE cpp_err) if (cpp_err) @@ -63,3 +67,14 @@ if (GRPC_CONNECTOR) endif() endif() +if (ENABLE_CRI_API_V1 AND ENABLE_SANDBOXER) + execute_process(COMMAND mkdir -p ${SANDBOX_PROTOS_OUT_PATH}) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/google/protobuf/any.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/google/protobuf/empty.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/google/protobuf/timestamp.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/github.com/containerd/containerd/api/types/sandbox.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/github.com/containerd/containerd/api/types/mount.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/github.com/containerd/containerd/api/types/platform.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox.proto) + PROTOC_GRPC_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox.proto) +endif() diff --git a/src/api/services/sandbox/github.com/containerd/containerd/api/types/mount.proto b/src/api/services/sandbox/github.com/containerd/containerd/api/types/mount.proto new file mode 100644 index 000000000..54e0a0cdd --- /dev/null +++ b/src/api/services/sandbox/github.com/containerd/containerd/api/types/mount.proto @@ -0,0 +1,43 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +syntax = "proto3"; + +package containerd.types; + +option go_package = "github.com/containerd/containerd/api/types;types"; + +// Mount describes mounts for a container. +// +// This type is the lingua franca of ContainerD. All services provide mounts +// to be used with the container at creation time. +// +// The Mount type follows the structure of the mount syscall, including a type, +// source, target and options. +message Mount { + // Type defines the nature of the mount. + string type = 1; + + // Source specifies the name of the mount. Depending on mount type, this + // may be a volume name or a host path, or even ignored. + string source = 2; + + // Target path in container + string target = 3; + + // Options specifies zero or more fstab style mount options. + repeated string options = 4; +} diff --git a/src/api/services/sandbox/github.com/containerd/containerd/api/types/platform.proto b/src/api/services/sandbox/github.com/containerd/containerd/api/types/platform.proto new file mode 100644 index 000000000..b6088251f --- /dev/null +++ b/src/api/services/sandbox/github.com/containerd/containerd/api/types/platform.proto @@ -0,0 +1,29 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +syntax = "proto3"; + +package containerd.types; + +option go_package = "github.com/containerd/containerd/api/types;types"; + +// Platform follows the structure of the OCI platform specification, from +// descriptors. +message Platform { + string os = 1; + string architecture = 2; + string variant = 3; +} diff --git a/src/api/services/sandbox/github.com/containerd/containerd/api/types/sandbox.proto b/src/api/services/sandbox/github.com/containerd/containerd/api/types/sandbox.proto new file mode 100644 index 000000000..7b9d196b6 --- /dev/null +++ b/src/api/services/sandbox/github.com/containerd/containerd/api/types/sandbox.proto @@ -0,0 +1,53 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +syntax = "proto3"; + +package containerd.types; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/containerd/containerd/api/types;types"; + +// Sandbox represents a sandbox metadata object that keeps all info required by controller to +// work with a particular instance. +message Sandbox { + // SandboxID is a unique instance identifier within namespace + string sandbox_id = 1; + message Runtime { + // Name is the name of the runtime. + string name = 1; + // Options specify additional runtime initialization options for the shim (this data will be available in StartShim). + // Typically this data expected to be runtime shim implementation specific. + google.protobuf.Any options = 2; + } + // Runtime specifies which runtime to use for executing this container. + Runtime runtime = 2; + // Spec is sandbox configuration (kin of OCI runtime spec), spec's data will be written to a config.json file in the + // bundle directory (similary to OCI spec). + google.protobuf.Any spec = 3; + // Sandboxer is the name of the sandbox controller who manages the sandbox. + string sandboxer = 4; + // Labels provides an area to include arbitrary data on containers. + map labels = 5; + // CreatedAt is the time the container was first created. + google.protobuf.Timestamp created_at = 6; + // UpdatedAt is the last time the container was mutated. + google.protobuf.Timestamp updated_at = 7; + // Extensions allow clients to provide optional blobs that can be handled by runtime. + map extensions = 8; +} diff --git a/src/api/services/sandbox/google/protobuf/any.proto b/src/api/services/sandbox/google/protobuf/any.proto new file mode 100644 index 000000000..c9be85416 --- /dev/null +++ b/src/api/services/sandbox/google/protobuf/any.proto @@ -0,0 +1,155 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/any"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/src/api/services/sandbox/google/protobuf/empty.proto b/src/api/services/sandbox/google/protobuf/empty.proto new file mode 100644 index 000000000..03cacd233 --- /dev/null +++ b/src/api/services/sandbox/google/protobuf/empty.proto @@ -0,0 +1,52 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/empty"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "EmptyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// A generic empty message that you can re-use to avoid defining duplicated +// empty messages in your APIs. A typical example is to use it as the request +// or the response type of an API method. For instance: +// +// service Foo { +// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +// } +// +// The JSON representation for `Empty` is empty JSON object `{}`. +message Empty {} diff --git a/src/api/services/sandbox/google/protobuf/timestamp.proto b/src/api/services/sandbox/google/protobuf/timestamp.proto new file mode 100644 index 000000000..cd357864a --- /dev/null +++ b/src/api/services/sandbox/google/protobuf/timestamp.proto @@ -0,0 +1,138 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/timestamp"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TimestampProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Timestamp represents a point in time independent of any time zone or local +// calendar, encoded as a count of seconds and fractions of seconds at +// nanosecond resolution. The count is relative to an epoch at UTC midnight on +// January 1, 1970, in the proleptic Gregorian calendar which extends the +// Gregorian calendar backwards to year one. +// +// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +// second table is needed for interpretation, using a [24-hour linear +// smear](https://developers.google.com/time/smear). +// +// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +// restricting to that range, we ensure that we can convert to and from [RFC +// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required. A proto3 JSON serializer should always use UTC (as indicated by +// "Z") when printing the Timestamp type and a proto3 JSON parser should be +// able to accept both UTC and other timezones (as indicated by an offset). +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard +// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using +// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with +// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use +// the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D +// ) to obtain a formatter capable of generating timestamps in this format. +// +// +message Timestamp { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + int32 nanos = 2; +} diff --git a/src/api/services/sandbox/google/protobuf/wrappers.proto b/src/api/services/sandbox/google/protobuf/wrappers.proto new file mode 100644 index 000000000..9ee41e384 --- /dev/null +++ b/src/api/services/sandbox/google/protobuf/wrappers.proto @@ -0,0 +1,123 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Wrappers for primitive (non-message) types. These types are useful +// for embedding primitives in the `google.protobuf.Any` type and for places +// where we need to distinguish between the absence of a primitive +// typed field and its default value. +// +// These wrappers have no meaningful use within repeated fields as they lack +// the ability to detect presence on individual elements. +// These wrappers have no meaningful use within a map or a oneof since +// individual entries of a map or fields of a oneof can already detect presence. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/wrappers"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "WrappersProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// Wrapper message for `double`. +// +// The JSON representation for `DoubleValue` is JSON number. +message DoubleValue { + // The double value. + double value = 1; +} + +// Wrapper message for `float`. +// +// The JSON representation for `FloatValue` is JSON number. +message FloatValue { + // The float value. + float value = 1; +} + +// Wrapper message for `int64`. +// +// The JSON representation for `Int64Value` is JSON string. +message Int64Value { + // The int64 value. + int64 value = 1; +} + +// Wrapper message for `uint64`. +// +// The JSON representation for `UInt64Value` is JSON string. +message UInt64Value { + // The uint64 value. + uint64 value = 1; +} + +// Wrapper message for `int32`. +// +// The JSON representation for `Int32Value` is JSON number. +message Int32Value { + // The int32 value. + int32 value = 1; +} + +// Wrapper message for `uint32`. +// +// The JSON representation for `UInt32Value` is JSON number. +message UInt32Value { + // The uint32 value. + uint32 value = 1; +} + +// Wrapper message for `bool`. +// +// The JSON representation for `BoolValue` is JSON `true` and `false`. +message BoolValue { + // The bool value. + bool value = 1; +} + +// Wrapper message for `string`. +// +// The JSON representation for `StringValue` is JSON string. +message StringValue { + // The string value. + string value = 1; +} + +// Wrapper message for `bytes`. +// +// The JSON representation for `BytesValue` is JSON string. +message BytesValue { + // The bytes value. + bytes value = 1; +} diff --git a/src/api/services/sandbox/sandbox.proto b/src/api/services/sandbox/sandbox.proto new file mode 100644 index 000000000..74a1caf55 --- /dev/null +++ b/src/api/services/sandbox/sandbox.proto @@ -0,0 +1,210 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +syntax = "proto3"; + +// Sandbox is a v2 runtime extension that allows more complex execution environments for containers. +// This adds a notion of groups of containers that share same lifecycle and/or resources. +// A few good fits for sandbox can be: +// - A "pause" container in k8s, that acts as a parent process for child containers to hold network namespace. +// - (micro)VMs that launch a VM process and executes containers inside guest OS. +// containerd in this case remains implementation agnostic and delegates sandbox handling to runtimes. +// See proposal and discussion here: https://github.com/containerd/containerd/issues/4131 +package containerd.services.sandbox.v1; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +import "github.com/containerd/containerd/api/types/sandbox.proto"; +import "github.com/containerd/containerd/api/types/mount.proto"; +import "github.com/containerd/containerd/api/types/platform.proto"; + +option go_package = "github.com/containerd/containerd/api/services/sandbox/v1;sandbox"; + +// Store provides a metadata storage interface for sandboxes. Similarly to `Containers`, +// sandbox object includes info required to start a new instance, but no runtime state. +// When running a new sandbox instance, store objects are used as base type to create from. +service Store { + rpc Create(StoreCreateRequest) returns (StoreCreateResponse); + rpc Update(StoreUpdateRequest) returns (StoreUpdateResponse); + rpc Delete(StoreDeleteRequest) returns (StoreDeleteResponse); + rpc List(StoreListRequest) returns (StoreListResponse); + rpc Get(StoreGetRequest) returns (StoreGetResponse); +} + +message StoreCreateRequest { + containerd.types.Sandbox sandbox = 1; +} + +message StoreCreateResponse { + containerd.types.Sandbox sandbox = 1; +} + +message StoreUpdateRequest { + containerd.types.Sandbox sandbox = 1; + repeated string fields = 2; +} + +message StoreUpdateResponse { + containerd.types.Sandbox sandbox = 1; +} + +message StoreDeleteRequest { + string sandbox_id = 1; +} + +message StoreDeleteResponse {} + +message StoreListRequest { + repeated string filters = 1; +} + +message StoreListResponse { + repeated containerd.types.Sandbox list = 1; +} + +message StoreGetRequest { + string sandbox_id = 1; +} + +message StoreGetResponse { + containerd.types.Sandbox sandbox = 1; +} + +// Controller is an interface to manage runtime sandbox instances. +service Controller { + rpc Create(ControllerCreateRequest) returns (ControllerCreateResponse); + rpc Start(ControllerStartRequest) returns (ControllerStartResponse); + rpc Platform(ControllerPlatformRequest) returns (ControllerPlatformResponse); + rpc Prepare(PrepareRequest) returns (PrepareResponse); + rpc Purge(PurgeRequest) returns (PurgeResponse); + rpc UpdateResources(UpdateResourcesRequest) returns (UpdateResourcesResponse); + rpc Stop(ControllerStopRequest) returns (ControllerStopResponse); + rpc Wait(ControllerWaitRequest) returns (ControllerWaitResponse); + rpc Status(ControllerStatusRequest) returns (ControllerStatusResponse); + rpc Shutdown(ControllerShutdownRequest) returns (ControllerShutdownResponse); +} + +message ControllerCreateRequest { + string sandboxer = 1; + string sandbox_id = 2; + repeated containerd.types.Mount rootfs = 3; + google.protobuf.Any options = 4; + string netns_path = 5; +} + +message ControllerCreateResponse { + string sandbox_id = 1; +} + +message ControllerStartRequest { + string sandboxer = 1; + string sandbox_id = 2; +} + +message ControllerStartResponse { + string sandbox_id = 1; + uint32 pid = 2; + google.protobuf.Timestamp created_at = 3; + map labels = 4; +} + +message ControllerPlatformRequest { + string sandboxer = 1; + string sandbox_id = 2; +} + +message ControllerPlatformResponse { + containerd.types.Platform platform = 1; +} + +message ControllerStopRequest { + string sandboxer = 1; + string sandbox_id = 2; + uint32 timeout_secs = 3; +} + +message ControllerStopResponse {} + +message ControllerWaitRequest { + string sandboxer = 1; + string sandbox_id = 2; +} + +message ControllerWaitResponse { + uint32 exit_status = 1; + google.protobuf.Timestamp exited_at = 2; +} + +message ControllerStatusRequest { + string sandboxer = 1; + string sandbox_id = 2; + bool verbose = 3; +} + +message ControllerStatusResponse { + string sandbox_id = 1; + uint32 pid = 2; + string state = 3; + string task_address = 4; + map info = 5; + google.protobuf.Timestamp created_at = 6; + google.protobuf.Timestamp exited_at = 7; + google.protobuf.Any extra = 8; +} + +message ControllerShutdownRequest { + string sandboxer = 1; + string sandbox_id = 2; +} + +message ControllerShutdownResponse {} + +message PrepareRequest { + string sandboxer = 1; + string sandbox_id = 2; + string container_id = 3; + string exec_id = 4; + google.protobuf.Any spec = 5; + repeated containerd.types.Mount rootfs = 6; + string stdin = 7; + string stdout = 8; + string stderr = 9; + bool terminal = 10; +} + +message PrepareResponse { + string bundle = 1; +} + +message PurgeRequest { + string sandboxer = 1; + string sandbox_id = 2; + string container_id = 3; + string exec_id = 4; +} + +message PurgeResponse {} + +message UpdateResourcesRequest { + string sandboxer = 1; + string sandbox_id = 2; + string container_id = 3; + google.protobuf.Any resources = 4; + map annotations = 5; +} + +message UpdateResourcesResponse {} -- Gitee From 7c51e111b5910c6af803cee8ece1b255631f6044 Mon Sep 17 00:00:00 2001 From: xuxuepeng Date: Fri, 14 Jul 2023 10:42:14 +0800 Subject: [PATCH 2/2] Add grpc sandboxer client and UT Signed-off-by: xuxuepeng --- cmake/protoc.cmake | 6 +- .../sandbox/google/protobuf/wrappers.proto | 123 ------ src/api/services/sandbox/sandbox.proto | 6 +- .../api => sandbox}/types/mount.proto | 0 .../api => sandbox}/types/platform.proto | 0 .../api => sandbox}/types/sandbox.proto | 0 src/daemon/sandbox/controller/controller.h | 4 +- .../controller/sandboxer/CMakeLists.txt | 4 + .../sandboxer/client/CMakeLists.txt | 20 + .../sandboxer/client/grpc_sandboxer_client.cc | 377 +++++++++++++++++ .../sandboxer/client/grpc_sandboxer_client.h | 84 ++++ test/CMakeLists.txt | 1 + test/mocks/controller_stub_mock.cc | 141 +++++++ test/mocks/controller_stub_mock.h | 51 +++ test/sandbox/CMakeLists.txt | 3 + test/sandbox/controller/CMakeLists.txt | 3 + .../controller/sandboxer/CMakeLists.txt | 3 + .../sandboxer/client/CMakeLists.txt | 37 ++ .../sandboxer/client/sandboxer_client_ut.cc | 382 ++++++++++++++++++ 19 files changed, 1114 insertions(+), 131 deletions(-) delete mode 100644 src/api/services/sandbox/google/protobuf/wrappers.proto rename src/api/services/sandbox/{github.com/containerd/containerd/api => sandbox}/types/mount.proto (100%) rename src/api/services/sandbox/{github.com/containerd/containerd/api => sandbox}/types/platform.proto (100%) rename src/api/services/sandbox/{github.com/containerd/containerd/api => sandbox}/types/sandbox.proto (100%) create mode 100755 src/daemon/sandbox/controller/sandboxer/client/CMakeLists.txt create mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc create mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h create mode 100644 test/mocks/controller_stub_mock.cc create mode 100644 test/mocks/controller_stub_mock.h create mode 100644 test/sandbox/CMakeLists.txt create mode 100644 test/sandbox/controller/CMakeLists.txt create mode 100644 test/sandbox/controller/sandboxer/CMakeLists.txt create mode 100644 test/sandbox/controller/sandboxer/client/CMakeLists.txt create mode 100644 test/sandbox/controller/sandboxer/client/sandboxer_client_ut.cc diff --git a/cmake/protoc.cmake b/cmake/protoc.cmake index 9172fe494..80c086872 100644 --- a/cmake/protoc.cmake +++ b/cmake/protoc.cmake @@ -72,9 +72,9 @@ if (ENABLE_CRI_API_V1 AND ENABLE_SANDBOXER) PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/google/protobuf/any.proto) PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/google/protobuf/empty.proto) PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/google/protobuf/timestamp.proto) - PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/github.com/containerd/containerd/api/types/sandbox.proto) - PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/github.com/containerd/containerd/api/types/mount.proto) - PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/github.com/containerd/containerd/api/types/platform.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/sandbox.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/mount.proto) + PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/platform.proto) PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox.proto) PROTOC_GRPC_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox.proto) endif() diff --git a/src/api/services/sandbox/google/protobuf/wrappers.proto b/src/api/services/sandbox/google/protobuf/wrappers.proto deleted file mode 100644 index 9ee41e384..000000000 --- a/src/api/services/sandbox/google/protobuf/wrappers.proto +++ /dev/null @@ -1,123 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Wrappers for primitive (non-message) types. These types are useful -// for embedding primitives in the `google.protobuf.Any` type and for places -// where we need to distinguish between the absence of a primitive -// typed field and its default value. -// -// These wrappers have no meaningful use within repeated fields as they lack -// the ability to detect presence on individual elements. -// These wrappers have no meaningful use within a map or a oneof since -// individual entries of a map or fields of a oneof can already detect presence. - -syntax = "proto3"; - -package google.protobuf; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option cc_enable_arenas = true; -option go_package = "github.com/golang/protobuf/ptypes/wrappers"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "WrappersProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; - -// Wrapper message for `double`. -// -// The JSON representation for `DoubleValue` is JSON number. -message DoubleValue { - // The double value. - double value = 1; -} - -// Wrapper message for `float`. -// -// The JSON representation for `FloatValue` is JSON number. -message FloatValue { - // The float value. - float value = 1; -} - -// Wrapper message for `int64`. -// -// The JSON representation for `Int64Value` is JSON string. -message Int64Value { - // The int64 value. - int64 value = 1; -} - -// Wrapper message for `uint64`. -// -// The JSON representation for `UInt64Value` is JSON string. -message UInt64Value { - // The uint64 value. - uint64 value = 1; -} - -// Wrapper message for `int32`. -// -// The JSON representation for `Int32Value` is JSON number. -message Int32Value { - // The int32 value. - int32 value = 1; -} - -// Wrapper message for `uint32`. -// -// The JSON representation for `UInt32Value` is JSON number. -message UInt32Value { - // The uint32 value. - uint32 value = 1; -} - -// Wrapper message for `bool`. -// -// The JSON representation for `BoolValue` is JSON `true` and `false`. -message BoolValue { - // The bool value. - bool value = 1; -} - -// Wrapper message for `string`. -// -// The JSON representation for `StringValue` is JSON string. -message StringValue { - // The string value. - string value = 1; -} - -// Wrapper message for `bytes`. -// -// The JSON representation for `BytesValue` is JSON string. -message BytesValue { - // The bytes value. - bytes value = 1; -} diff --git a/src/api/services/sandbox/sandbox.proto b/src/api/services/sandbox/sandbox.proto index 74a1caf55..78ea3233e 100644 --- a/src/api/services/sandbox/sandbox.proto +++ b/src/api/services/sandbox/sandbox.proto @@ -28,9 +28,9 @@ package containerd.services.sandbox.v1; import "google/protobuf/any.proto"; import "google/protobuf/timestamp.proto"; -import "github.com/containerd/containerd/api/types/sandbox.proto"; -import "github.com/containerd/containerd/api/types/mount.proto"; -import "github.com/containerd/containerd/api/types/platform.proto"; +import "sandbox/types/sandbox.proto"; +import "sandbox/types/mount.proto"; +import "sandbox/types/platform.proto"; option go_package = "github.com/containerd/containerd/api/services/sandbox/v1;sandbox"; diff --git a/src/api/services/sandbox/github.com/containerd/containerd/api/types/mount.proto b/src/api/services/sandbox/sandbox/types/mount.proto similarity index 100% rename from src/api/services/sandbox/github.com/containerd/containerd/api/types/mount.proto rename to src/api/services/sandbox/sandbox/types/mount.proto diff --git a/src/api/services/sandbox/github.com/containerd/containerd/api/types/platform.proto b/src/api/services/sandbox/sandbox/types/platform.proto similarity index 100% rename from src/api/services/sandbox/github.com/containerd/containerd/api/types/platform.proto rename to src/api/services/sandbox/sandbox/types/platform.proto diff --git a/src/api/services/sandbox/github.com/containerd/containerd/api/types/sandbox.proto b/src/api/services/sandbox/sandbox/types/sandbox.proto similarity index 100% rename from src/api/services/sandbox/github.com/containerd/containerd/api/types/sandbox.proto rename to src/api/services/sandbox/sandbox/types/sandbox.proto diff --git a/src/daemon/sandbox/controller/controller.h b/src/daemon/sandbox/controller/controller.h index 38c24c01d..22e8a78a1 100644 --- a/src/daemon/sandbox/controller/controller.h +++ b/src/daemon/sandbox/controller/controller.h @@ -31,7 +31,7 @@ struct ControllerMountInfo { std::string source; std::string destination; std::string type; - std::string options; + std::vector options; }; struct ControllerCreateParams { @@ -51,7 +51,7 @@ struct ControllerSandboxInfo { std::string id; uint32_t pid; uint64_t createdAt; - google::protobuf::Map &labels; + google::protobuf::Map labels; }; struct ControllerExitInfo { diff --git a/src/daemon/sandbox/controller/sandboxer/CMakeLists.txt b/src/daemon/sandbox/controller/sandboxer/CMakeLists.txt index 8a79d5aeb..087f5031b 100755 --- a/src/daemon/sandbox/controller/sandboxer/CMakeLists.txt +++ b/src/daemon/sandbox/controller/sandboxer/CMakeLists.txt @@ -1,11 +1,15 @@ # get current directory sources files aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} sandbox_controller_sandboxer_srcs) +add_subdirectory(client) + set(CONTROLLER_SANDBOXER_SRCS ${sandbox_controller_sandboxer_srcs} + ${CONTROLLER_SANDBOXER_CLIENT_SRCS} PARENT_SCOPE ) set(CONTROLLER_SANDBOXER_INCS ${CMAKE_CURRENT_SOURCE_DIR} + ${CONTROLLER_SANDBOXER_CLIENT_INCS} PARENT_SCOPE ) diff --git a/src/daemon/sandbox/controller/sandboxer/client/CMakeLists.txt b/src/daemon/sandbox/controller/sandboxer/client/CMakeLists.txt new file mode 100755 index 000000000..958ebaa51 --- /dev/null +++ b/src/daemon/sandbox/controller/sandboxer/client/CMakeLists.txt @@ -0,0 +1,20 @@ +# get current directory sources files +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} sandbox_controller_sandboxer_client_srcs) +aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox grpc_sandbox_api_srcs) +aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox/google/protobuf grpc_sandbox_google_protobuf_api_srcs) +aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox/sandbox/types sandbox_type_srcs) + + +set(CONTROLLER_SANDBOXER_CLIENT_SRCS + ${sandbox_controller_sandboxer_client_srcs} + ${grpc_sandbox_api_srcs} + ${grpc_sandbox_google_protobuf_api_srcs} + ${sandbox_type_srcs} + PARENT_SCOPE + ) + +set(CONTROLLER_SANDBOXER_CLIENT_INCS + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox + PARENT_SCOPE + ) diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc new file mode 100644 index 000000000..a4c3dc0d2 --- /dev/null +++ b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc @@ -0,0 +1,377 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. + * iSulad licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: xuxuepeng + * Create: 2023-07-10 + * Description: Sandboxer grpc client + ******************************************************************************/ + +#include +#include +#include +#include + +#include "grpc_sandboxer_client.h" +#include "sandbox/types/platform.pb.h" +#include "sandbox.pb.h" +#include "sandbox.grpc.pb.h" +#include "utils.h" +#include "isula_libutils/log.h" + +namespace sandbox { + +const uint64_t SECOND_TO_NANOS = 1000000000; + +SandboxerClient::SandboxerClient(const std::string &sandboxer, const std::string &address): + m_sandboxer(sandboxer), m_address(address) +{ + std::string unixPrefix(UNIX_SOCKET_PREFIX); + + // Only support unix domain socket + if (m_address.compare(0, unixPrefix.length(), unixPrefix) != 0) { + m_address = unixPrefix + m_address; + } + + stub_ = containerd::services::sandbox::v1::Controller::NewStub(grpc::CreateChannel(m_address, grpc::InsecureChannelCredentials())); +} + +void SandboxerClient::InitMountInfo(Mount &mount, const ControllerMountInfo &mountInfo) +{ + mount.set_type(mountInfo.type); + mount.set_source(mountInfo.source); + mount.set_target(mountInfo.destination); + for (const auto &option : mountInfo.options) { + mount.add_options(option); + } +} + +auto SandboxerClient::InitCreateRequest(containerd::services::sandbox::v1::ControllerCreateRequest &request, + const std::string &sandboxId, + const ControllerCreateParams ¶ms) -> bool +{ + if (params.config == nullptr) { + ERROR("Sandboxer controller create request failed, config is null"); + return false; + } + std::string configOptions; + auto status = google::protobuf::util::MessageToJsonString(*params.config, &configOptions); + if (!status.ok()) { + ERROR("Failed to convert pod config to json string, %s", status.ToString().c_str()); + return false; + } + request.mutable_options()->set_value(configOptions); + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + for (const auto &entry : params.mounts) { + if (entry != nullptr) { + Mount* mount = request.add_rootfs(); + InitMountInfo(*mount, *entry); + } + } + request.set_netns_path(params.netNSPath); + return true; +} + +auto SandboxerClient::Create(const std::string &sandboxId, const ControllerCreateParams ¶ms, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::ControllerCreateRequest request; + containerd::services::sandbox::v1::ControllerCreateResponse response; + grpc::Status status; + + if (!InitCreateRequest(request, sandboxId, params)) { + error.SetError("Failed to init create request for sandboxer create request, sandbox id: " + sandboxId); + return false; + } + + status = stub_->Create(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller create request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + return true; +} + +auto SandboxerClient::TimestampToNanos(const Timestamp ×tamp) -> uint64_t +{ + uint64_t nanos = 0; + + nanos = timestamp.seconds() * SECOND_TO_NANOS; + nanos += timestamp.nanos(); + + return nanos; +} + +void SandboxerClient::StartResponseToSandboxInfo(const containerd::services::sandbox::v1::ControllerStartResponse &response, + ControllerSandboxInfo &sandboxInfo) +{ + sandboxInfo.id = response.sandbox_id(); + sandboxInfo.pid = response.pid(); + sandboxInfo.createdAt = TimestampToNanos(response.created_at()); + sandboxInfo.labels = response.labels(); +} + +auto SandboxerClient::Start(const std::string &sandboxId, ControllerSandboxInfo &sandboxInfo, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::ControllerStartRequest request; + containerd::services::sandbox::v1::ControllerStartResponse response; + grpc::Status status; + + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + + status = stub_->Start(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller start request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + StartResponseToSandboxInfo(response, sandboxInfo); + + return true; +} + +auto SandboxerClient::InitPrepareRequest(containerd::services::sandbox::v1::PrepareRequest &request, + const std::string &sandboxId, const ControllerPrepareParams ¶ms) -> bool +{ + if (params.spec == nullptr) { + ERROR("Sandboxer controller prepare request failed, spec is null"); + return false; + } + request.mutable_spec()->set_value(*(params.spec)); + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + request.set_container_id(params.containerId); + request.set_exec_id(params.execId); + for (const auto &entry : params.rootfs) { + if (entry != nullptr) { + Mount* mount = request.add_rootfs(); + InitMountInfo(*mount, *entry); + } + } + if (params.streamInfo != nullptr) { + request.set_stdin(params.streamInfo->stdin); + request.set_stdout(params.streamInfo->stdout); + request.set_stderr(params.streamInfo->stderr); + request.set_terminal(params.streamInfo->terminal); + } else { + request.set_stdin(""); + request.set_stdout(""); + request.set_stderr(""); + request.set_terminal(false); + } + + return true; +} + +auto SandboxerClient::Prepare(const std::string &sandboxId, const ControllerPrepareParams ¶ms, std::string &bundle, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::PrepareRequest request; + containerd::services::sandbox::v1::PrepareResponse response; + grpc::Status status; + + if (!InitPrepareRequest(request, sandboxId, params)) { + error.SetError("Failed to init prepare request for sandboxer prepare request, sandbox id: " + sandboxId); + return false; + } + + status = stub_->Prepare(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller prepare request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + bundle = response.bundle(); + + return true; +} + +auto SandboxerClient::Purge(const std::string &sandboxId, const std::string &containerId, + const std::string &execId, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::PurgeRequest request; + containerd::services::sandbox::v1::PurgeResponse response; + grpc::Status status; + + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + request.set_container_id(containerId); + request.set_exec_id(execId); + + status = stub_->Purge(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller purge request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + return true; +} + +auto SandboxerClient::InitUpdateResourcesRequest(containerd::services::sandbox::v1::UpdateResourcesRequest &request, + const std::string &sandboxId, + const ControllerUpdateResourcesParams ¶ms) -> bool +{ + if (params.resources == nullptr) { + ERROR("Sandboxer controller update resources request failed, resources is null"); + return false; + } + request.mutable_resources()->set_value(*(params.resources)); + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + request.set_container_id(params.containerId); + request.mutable_annotations()->insert(params.annotations.begin(), params.annotations.end()); + return true; +} + +auto SandboxerClient::UpdateResources(const std::string &sandboxId, const ControllerUpdateResourcesParams ¶ms, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::UpdateResourcesRequest request; + containerd::services::sandbox::v1::UpdateResourcesResponse response; + grpc::Status status; + + if (!InitUpdateResourcesRequest(request, sandboxId, params)) { + error.SetError("Failed to init update-resources request for sandboxer update-resources request, sandbox id: " + sandboxId); + return false; + } + + status = stub_->UpdateResources(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller update resources request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + return true; +} + +void SandboxerClient::PlatformResponseToPlatformInfo(const containerd::services::sandbox::v1::ControllerPlatformResponse &response, + ControllerPlatformInfo &platformInfo) +{ + auto &platform = response.platform(); + platformInfo.os = platform.os(); + platformInfo.arch = platform.architecture(); + platformInfo.variant = platform.variant(); +} + +auto SandboxerClient::Platform(const std::string &sandboxId, ControllerPlatformInfo &platformInfo, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::ControllerPlatformRequest request; + containerd::services::sandbox::v1::ControllerPlatformResponse response; + grpc::Status status; + + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + + status = stub_->Platform(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller platform request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + PlatformResponseToPlatformInfo(response, platformInfo); + + return true; +} + +auto SandboxerClient::Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::ControllerStopRequest request; + containerd::services::sandbox::v1::ControllerStopResponse response; + grpc::Status status; + + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + request.set_timeout_secs(timeoutSecs); + + status = stub_->Stop(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller stop request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + return true; +} + +// TODO: async call +auto SandboxerClient::Wait(const std::string &sandboxId, Errors &error) -> bool +{ + return true; +} + +void SandboxerClient::StatusResponseToSandboxStatus(const containerd::services::sandbox::v1::ControllerStatusResponse &response, + ControllerSandboxStatus &sandboxStatus) +{ + sandboxStatus.id = response.sandbox_id(); + sandboxStatus.pid = response.pid(); + sandboxStatus.state = response.state(); + sandboxStatus.taskAddress = response.task_address(); + sandboxStatus.info.insert(response.info().begin(), response.info().end()); + sandboxStatus.createdAt = TimestampToNanos(response.created_at()); + sandboxStatus.exitedAt = TimestampToNanos(response.exited_at()); + sandboxStatus.extra = response.extra().value(); +} + +auto SandboxerClient::Status(const std::string &sandboxId, bool verbose, ControllerSandboxStatus &sandboxStatus, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::ControllerStatusRequest request; + containerd::services::sandbox::v1::ControllerStatusResponse response; + grpc::Status status; + + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + request.set_verbose(verbose); + + status = stub_->Status(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller status request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + StatusResponseToSandboxStatus(response, sandboxStatus); + + return true; +} + +auto SandboxerClient::Shutdown(const std::string &sandboxId, Errors &error) -> bool +{ + grpc::ClientContext context; + containerd::services::sandbox::v1::ControllerShutdownRequest request; + containerd::services::sandbox::v1::ControllerShutdownResponse response; + grpc::Status status; + + request.set_sandboxer(m_sandboxer); + request.set_sandbox_id(sandboxId); + + status = stub_->Shutdown(&context, request, &response); + if (!status.ok()) { + error.SetError(status.error_message()); + ERROR("Sandboxer controller shutdown request failed, error_code: %d: %s", status.error_code(), status.error_message().c_str()); + return false; + } + + return true; +} + +} // namespace diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h new file mode 100644 index 000000000..5d63c65e4 --- /dev/null +++ b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. + * iSulad licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: xuxuepeng + * Create: 2023-07-10 + * Description: Sandboxer grpc client + ******************************************************************************/ + +#ifndef DAEON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_H +#define DAEON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_H + +#include +#include + +#include "sandbox/types/mount.pb.h" +#include "sandbox.pb.h" +#include "sandbox.grpc.pb.h" +#include "controller.h" + +using containerd::types::Mount; +using google::protobuf::Timestamp; + +namespace sandbox { + +class SandboxerClient { +public: + SandboxerClient(const std::string &sandboxer, const std::string &address); + + ~SandboxerClient() = default; + + auto Create(const std::string &sandboxId, const ControllerCreateParams ¶ms, Errors &error) -> bool; + + auto Start(const std::string &sandboxId, ControllerSandboxInfo &sandboxInfo, Errors &error) -> bool; + + auto Platform(const std::string &sandboxId, ControllerPlatformInfo &platformInfo, Errors &error) -> bool; + + auto Prepare(const std::string &sandboxId, const ControllerPrepareParams ¶ms, std::string &bundle, Errors &error) -> bool; + + auto Purge(const std::string &sandboxId, const std::string &containerId, + const std::string &execId, Errors &error) -> bool; + + auto UpdateResources(const std::string &sandboxId, const ControllerUpdateResourcesParams ¶ms, Errors &error) -> bool; + + auto Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error) -> bool; + + auto Wait(const std::string &sandboxId, Errors &error) -> bool; + + auto Status(const std::string &sandboxId, bool verbose, ControllerSandboxStatus &sandboxStatus, Errors &error) -> bool; + + auto Shutdown(const std::string &sandboxId, Errors &error) -> bool; + +private: + void InitMountInfo(Mount &mount, const ControllerMountInfo &mountInfo); + auto InitCreateRequest(containerd::services::sandbox::v1::ControllerCreateRequest &request, + const std::string &sandboxId, + const ControllerCreateParams ¶ms) -> bool; + auto TimestampToNanos(const Timestamp ×tamp) -> uint64_t; + void StartResponseToSandboxInfo(const containerd::services::sandbox::v1::ControllerStartResponse &response, + ControllerSandboxInfo &sandboxInfo); + auto InitPrepareRequest(containerd::services::sandbox::v1::PrepareRequest &request, + const std::string &sandboxId, const ControllerPrepareParams ¶ms) -> bool; + auto InitUpdateResourcesRequest(containerd::services::sandbox::v1::UpdateResourcesRequest &request, + const std::string &sandboxId, + const ControllerUpdateResourcesParams ¶ms) -> bool; + void PlatformResponseToPlatformInfo(const containerd::services::sandbox::v1::ControllerPlatformResponse &response, + ControllerPlatformInfo &platformInfo); + void StatusResponseToSandboxStatus(const containerd::services::sandbox::v1::ControllerStatusResponse &response, + ControllerSandboxStatus &sandboxStatus); + std::string m_sandboxer; + std::string m_address; + +protected: + std::unique_ptr stub_; +}; + +} // namespace +#endif // DAEON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_H \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3033350a1..a58d4e948 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -42,6 +42,7 @@ IF(ENABLE_UT) add_subdirectory(image) add_subdirectory(cmd) add_subdirectory(runtime) + add_subdirectory(sandbox) add_subdirectory(specs) add_subdirectory(services) add_subdirectory(network) diff --git a/test/mocks/controller_stub_mock.cc b/test/mocks/controller_stub_mock.cc new file mode 100644 index 000000000..1ea7a43dd --- /dev/null +++ b/test/mocks/controller_stub_mock.cc @@ -0,0 +1,141 @@ +#include "controller_stub_mock.h" + +namespace containerd { +namespace services { +namespace sandbox { +namespace v1 { + +std::unique_ptr NewMockControllerStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) { + std::unique_ptr stub(new MockControllerStub()); + return stub; +} + +/* Rewrite all the functions for Controller::Stub with trival implementation */ +::grpc::Status Controller::Stub::Create(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerCreateRequest& request, ::containerd::services::sandbox::v1::ControllerCreateResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::Start(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStartRequest& request, ::containerd::services::sandbox::v1::ControllerStartResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::Platform(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerPlatformRequest& request, ::containerd::services::sandbox::v1::ControllerPlatformResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::Prepare(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PrepareRequest& request, ::containerd::services::sandbox::v1::PrepareResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::Purge(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PurgeRequest& request, ::containerd::services::sandbox::v1::PurgeResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::UpdateResources(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::UpdateResourcesRequest& request, ::containerd::services::sandbox::v1::UpdateResourcesResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::Stop(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStopRequest& request, ::containerd::services::sandbox::v1::ControllerStopResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::Wait(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerWaitRequest& request, ::containerd::services::sandbox::v1::ControllerWaitResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStatusRequest& request, ::containerd::services::sandbox::v1::ControllerStatusResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::Status Controller::Stub::Shutdown(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerShutdownRequest& request, ::containerd::services::sandbox::v1::ControllerShutdownResponse* response) { + return ::grpc::Status::OK; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerCreateResponse>* Controller::Stub::AsyncCreateRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerCreateRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerCreateResponse>* Controller::Stub::PrepareAsyncCreateRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerCreateRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerStartResponse>* Controller::Stub::AsyncStartRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStartRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerStartResponse>* Controller::Stub::PrepareAsyncStartRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStartRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerPlatformResponse>* Controller::Stub::AsyncPlatformRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerPlatformRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerPlatformResponse>* Controller::Stub::PrepareAsyncPlatformRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerPlatformRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::PrepareResponse>* Controller::Stub::AsyncPrepareRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PrepareRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::PrepareResponse>* Controller::Stub::PrepareAsyncPrepareRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PrepareRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::PurgeResponse>* Controller::Stub::AsyncPurgeRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PurgeRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::PurgeResponse>* Controller::Stub::PrepareAsyncPurgeRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PurgeRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::UpdateResourcesResponse>* Controller::Stub::AsyncUpdateResourcesRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::UpdateResourcesRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::UpdateResourcesResponse>* Controller::Stub::PrepareAsyncUpdateResourcesRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::UpdateResourcesRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerStopResponse>* Controller::Stub::AsyncStopRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStopRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerStopResponse>* Controller::Stub::PrepareAsyncStopRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStopRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerWaitResponse>* Controller::Stub::AsyncWaitRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerWaitRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerWaitResponse>* Controller::Stub::PrepareAsyncWaitRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerWaitRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerStatusResponse>* Controller::Stub::AsyncStatusRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStatusRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerStatusResponse>* Controller::Stub::PrepareAsyncStatusRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStatusRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerShutdownResponse>* Controller::Stub::AsyncShutdownRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerShutdownRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +::grpc::ClientAsyncResponseReader< ::containerd::services::sandbox::v1::ControllerShutdownResponse>* Controller::Stub::PrepareAsyncShutdownRaw(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerShutdownRequest& request, ::grpc::CompletionQueue* cq) { + return nullptr; +} + +// Return null_ptr for the original NewStub function, so that we can use the mock stub. +std::unique_ptr Controller::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) { + return nullptr; +} + +} // namespace v1 +} // namespace sandbox +} // namespace services +} // namespace containerd \ No newline at end of file diff --git a/test/mocks/controller_stub_mock.h b/test/mocks/controller_stub_mock.h new file mode 100644 index 000000000..40f67e78e --- /dev/null +++ b/test/mocks/controller_stub_mock.h @@ -0,0 +1,51 @@ +#include +#include "sandbox.grpc.pb.h" + +namespace containerd { +namespace services { +namespace sandbox { +namespace v1 { + +// MockControllerStub is a mock implementation of the Controller::StubInterface interface. +class MockControllerStub final : public Controller::StubInterface { +public: + MockControllerStub() = default; + MOCK_METHOD3(Create, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerCreateRequest& request, ::containerd::services::sandbox::v1::ControllerCreateResponse* response)); + MOCK_METHOD3(Start, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStartRequest& request, ::containerd::services::sandbox::v1::ControllerStartResponse* response)); + MOCK_METHOD3(Platform, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerPlatformRequest& request, ::containerd::services::sandbox::v1::ControllerPlatformResponse* response)); + MOCK_METHOD3(Prepare, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PrepareRequest& request, ::containerd::services::sandbox::v1::PrepareResponse* response)); + MOCK_METHOD3(Purge, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PurgeRequest& request, ::containerd::services::sandbox::v1::PurgeResponse* response)); + MOCK_METHOD3(UpdateResources, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::UpdateResourcesRequest& request, ::containerd::services::sandbox::v1::UpdateResourcesResponse* response)); + MOCK_METHOD3(Stop, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStopRequest& request, ::containerd::services::sandbox::v1::ControllerStopResponse* response)); + MOCK_METHOD3(Wait, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerWaitRequest& request, ::containerd::services::sandbox::v1::ControllerWaitResponse* response)); + MOCK_METHOD3(Status, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStatusRequest& request, ::containerd::services::sandbox::v1::ControllerStatusResponse* response)); + MOCK_METHOD3(Shutdown, ::grpc::Status(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerShutdownRequest& request, ::containerd::services::sandbox::v1::ControllerShutdownResponse* response)); +private: + MOCK_METHOD3(AsyncCreateRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerCreateResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerCreateRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncCreateRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerCreateResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerCreateRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncStartRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerStartResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStartRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncStartRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerStartResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStartRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncPlatformRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerPlatformResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerPlatformRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncPlatformRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerPlatformResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerPlatformRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncPrepareRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::PrepareResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PrepareRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncPrepareRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::PrepareResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PrepareRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncPurgeRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::PurgeResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PurgeRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncPurgeRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::PurgeResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::PurgeRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncUpdateResourcesRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::UpdateResourcesResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::UpdateResourcesRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncUpdateResourcesRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::UpdateResourcesResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::UpdateResourcesRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncStopRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerStopResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStopRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncStopRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerStopResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStopRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncWaitRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerWaitResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerWaitRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncWaitRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerWaitResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerWaitRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncStatusRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerStatusResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStatusRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncStatusRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerStatusResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerStatusRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(AsyncShutdownRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerShutdownResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerShutdownRequest& request, ::grpc::CompletionQueue* cq)); + MOCK_METHOD3(PrepareAsyncShutdownRaw, ::grpc::ClientAsyncResponseReaderInterface< ::containerd::services::sandbox::v1::ControllerShutdownResponse>*(::grpc::ClientContext* context, const ::containerd::services::sandbox::v1::ControllerShutdownRequest& request, ::grpc::CompletionQueue* cq)); +}; + +std::unique_ptr NewMockControllerStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options); + +} // namespace v1 +} // namespace sandbox +} // namespace services +} // namespace containerd diff --git a/test/sandbox/CMakeLists.txt b/test/sandbox/CMakeLists.txt new file mode 100644 index 000000000..89d1a4143 --- /dev/null +++ b/test/sandbox/CMakeLists.txt @@ -0,0 +1,3 @@ +project(iSulad_UT) + +add_subdirectory(controller) diff --git a/test/sandbox/controller/CMakeLists.txt b/test/sandbox/controller/CMakeLists.txt new file mode 100644 index 000000000..d076d4268 --- /dev/null +++ b/test/sandbox/controller/CMakeLists.txt @@ -0,0 +1,3 @@ +project(iSulad_UT) + +add_subdirectory(sandboxer) diff --git a/test/sandbox/controller/sandboxer/CMakeLists.txt b/test/sandbox/controller/sandboxer/CMakeLists.txt new file mode 100644 index 000000000..c3cd27f5e --- /dev/null +++ b/test/sandbox/controller/sandboxer/CMakeLists.txt @@ -0,0 +1,3 @@ +project(iSulad_UT) + +add_subdirectory(client) diff --git a/test/sandbox/controller/sandboxer/client/CMakeLists.txt b/test/sandbox/controller/sandboxer/client/CMakeLists.txt new file mode 100644 index 000000000..c0dce57a4 --- /dev/null +++ b/test/sandbox/controller/sandboxer/client/CMakeLists.txt @@ -0,0 +1,37 @@ +project(iSulad_UT) + +SET(EXE sandbox_controller_ut) + +aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox/sandbox/types sandbox_type_srcs) + +add_executable(${EXE} + ${sandbox_type_srcs} + ${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox/sandbox.pb.cc + ${CMAKE_BINARY_DIR}/grpc/src/api/services/cri/v1/api_v1.pb.cc + ${CMAKE_BINARY_DIR}/grpc/src/api/services/cri/gogo.pb.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/entry/cri/errors.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../test/mocks/controller_stub_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/sandboxer_client_ut.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../test/mocks + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/entry/cri + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/sandbox/controller + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/sandbox/controller/sandboxer + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/sandbox/controller/sandboxer/client + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/common + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/sha256 + ${CMAKE_BINARY_DIR}/grpc/src/api/services/cri + ${CMAKE_BINARY_DIR}/grpc/src/api/services/cri/v1 + ${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox + ${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox/google/protobuf + ${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox/sandbox/types +) + +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} libutils_ut -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) +add_test(NAME ${EXE} COMMAND ${EXE} --gtest_output=xml:${EXE}-Results.xml) +set_tests_properties(${EXE} PROPERTIES TIMEOUT 120) diff --git a/test/sandbox/controller/sandboxer/client/sandboxer_client_ut.cc b/test/sandbox/controller/sandboxer/client/sandboxer_client_ut.cc new file mode 100644 index 000000000..ee2314aaa --- /dev/null +++ b/test/sandbox/controller/sandboxer/client/sandboxer_client_ut.cc @@ -0,0 +1,382 @@ +#include "gtest/gtest.h" +#include "controller_stub_mock.h" +#include "grpc_sandboxer_client.h" +#include "controller.h" + +const std::string DUMMY_SANDBOX_ID = "604db93a33ec4c7787e4f369338f5887"; +const std::string DUMMY_CONTAINER_ID = "504db93a32ec4c9789e4d369a38f3889"; +const std::string DUMMY_EXEC_ID = "504db93a32ec4c9789e4d369a38f37765"; +const uint64_t SECOND_TO_NANOS = 1000000000; +const uint64_t DUMMY_CREATE_AT = 1588 * SECOND_TO_NANOS + 1588; +const std::string DUMMY_TASK_ADDRESS = "vsock://18982:1"; + +class SandboxerClientWrapper : public sandbox::SandboxerClient { +public: + SandboxerClientWrapper(const std::string &sandboxer, const std::string &address) : sandbox::SandboxerClient(sandboxer, address) {} + + void UpdateStub(std::unique_ptr stub) { + stub_ = std::move(stub); + } + + containerd::services::sandbox::v1::Controller::StubInterface &GetStub() { + return *stub_; + } +}; + +class ControllerSandboxerTest : public testing::Test { +protected: + void SetUp() override { + m_sandboxer = "sandboxer"; + m_address = "/tmp/sandboxer.sock"; + m_sandboxerClient = std::move(std::unique_ptr(new SandboxerClientWrapper(m_sandboxer, m_address))); + // Create a mock stub. + auto stub = std::unique_ptr( + new containerd::services::sandbox::v1::MockControllerStub() + ); + // Update the stub in the sandboxer client. + m_sandboxerClient->UpdateStub(std::move(stub)); + } + + containerd::services::sandbox::v1::MockControllerStub &GetStub() { + return dynamic_cast(m_sandboxerClient->GetStub()); + } + + void TearDown() override { + m_sandboxerClient.reset(); + } + + std::string m_sandboxer; + std::string m_address; + + std::unique_ptr m_sandboxerClient; +}; + +static std::unique_ptr CreateTestMountInfo() { + std::unique_ptr mountInfo(new sandbox::ControllerMountInfo()); + mountInfo->source = "/rootfs"; + mountInfo->destination = "/rootfs"; + mountInfo->type = "bind"; + return mountInfo; +} + +static std::unique_ptr CreateTestCreateParams() { + std::unique_ptr params(new sandbox::ControllerCreateParams()); + params->config = std::make_shared(); + params->netNSPath = "/proc/1/ns/net"; + params->mounts.push_back(std::move(CreateTestMountInfo())); + return params; +} + +static std::unique_ptr CreateTestGrpcStartResponse() { + std::unique_ptr response(new containerd::services::sandbox::v1::ControllerStartResponse()); + response->set_sandbox_id(DUMMY_SANDBOX_ID); + response->set_pid(1); + response->mutable_created_at()->set_seconds(DUMMY_CREATE_AT/SECOND_TO_NANOS); + response->mutable_created_at()->set_nanos(DUMMY_CREATE_AT%SECOND_TO_NANOS); + response->mutable_labels()->insert({"label1", "value1"}); + return response; +} + +// Create platform response for test. +static std::unique_ptr CreateTestPlatformResponse() { + std::unique_ptr response( + new containerd::services::sandbox::v1::ControllerPlatformResponse() + ); + response->mutable_platform()->set_os("linux"); + response->mutable_platform()->set_architecture("amd64"); + response->mutable_platform()->set_variant("ubuntu"); + return response; +} + +static std::unique_ptr CreateTestStreamInfo() { + std::unique_ptr streamInfo(new sandbox::ControllerStreamInfo()); + streamInfo->stdin = "/tmp/stdin"; + streamInfo->stdout = "/tmp/stdout"; + streamInfo->stderr = "/tmp/stderr"; + streamInfo->terminal = true; + return streamInfo; +} + +static std::unique_ptr CreateTestPrepareParams() { + std::unique_ptr params(new sandbox::ControllerPrepareParams()); + params->containerId = DUMMY_CONTAINER_ID; + params->execId = DUMMY_EXEC_ID; + params->spec = std::unique_ptr(new std::string("{spec: test}")); + params->rootfs.push_back(std::move(CreateTestMountInfo())); + params->rootfs.push_back(std::move(CreateTestMountInfo())); + params->streamInfo = CreateTestStreamInfo(); + return params; +} + +static std::unique_ptr CreateTestUpdateResourcesParams(google::protobuf::Map &annotations) { + std::unique_ptr resources(new std::string("{cpu: 12}")); + std::unique_ptr params( + new sandbox::ControllerUpdateResourcesParams{DUMMY_SANDBOX_ID, std::move(resources), annotations} + ); + return params; +} + +// Create status response for test +static std::unique_ptr CreateTestStatusResponse() { + std::unique_ptr response( + new containerd::services::sandbox::v1::ControllerStatusResponse() + ); + response->set_sandbox_id(DUMMY_SANDBOX_ID); + response->set_state("running"); + response->set_pid(1); + response->set_task_address(DUMMY_TASK_ADDRESS); + response->mutable_created_at()->set_seconds(DUMMY_CREATE_AT/SECOND_TO_NANOS); + response->mutable_created_at()->set_nanos(DUMMY_CREATE_AT%SECOND_TO_NANOS); + response->mutable_exited_at()->set_seconds(DUMMY_CREATE_AT/SECOND_TO_NANOS); + response->mutable_exited_at()->set_nanos(DUMMY_CREATE_AT%SECOND_TO_NANOS); + response->mutable_info()->insert({"info1", "value1"}); + response->mutable_extra()->set_value("{extra: test}"); + return response; +} + +/************* Unit tests for Create *************/ +TEST_F(ControllerSandboxerTest, CreateTestSucceed) { + Errors err; + std::unique_ptr params = CreateTestCreateParams(); + // Fake a grpc create response. + containerd::services::sandbox::v1::ControllerCreateResponse response; + response.set_sandbox_id(DUMMY_SANDBOX_ID); + // Set response to return sandbox_id, and return OK for stub_->Create(). + EXPECT_CALL(GetStub(), Create).Times(1).WillOnce(testing::DoAll(testing::SetArgPointee<2>(response), testing::Return(grpc::Status::OK))); + EXPECT_TRUE(m_sandboxerClient->Create(DUMMY_SANDBOX_ID, *params, err)); + EXPECT_TRUE(err.Empty()); +} + +TEST_F(ControllerSandboxerTest, CreateTestNullConfig) { + Errors err; + std::unique_ptr params(new sandbox::ControllerCreateParams()); + params->config = nullptr; + // Stub should not be called + EXPECT_CALL(GetStub(), Create).Times(0); + EXPECT_FALSE(m_sandboxerClient->Create(DUMMY_SANDBOX_ID, *params, err)); + EXPECT_FALSE(err.Empty()); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("Failed to init create request for sandboxer create request")); +} + +TEST_F(ControllerSandboxerTest, CreateTestNullMount) { + Errors err; + std::unique_ptr params = CreateTestCreateParams(); + params->mounts.push_back(nullptr); + containerd::services::sandbox::v1::ControllerCreateRequest request; + // Save request to check mount size. + EXPECT_CALL(GetStub(), Create).Times(1).WillOnce(testing::DoAll(testing::SaveArg<1>(&request), testing::Return(grpc::Status::OK))); + EXPECT_TRUE(m_sandboxerClient->Create(DUMMY_SANDBOX_ID, *params, err)); + // The nullptr pushed in params should not be counted. + EXPECT_EQ(request.rootfs_size(), 1); + EXPECT_TRUE(err.Empty()); +} + +TEST_F(ControllerSandboxerTest, CreateTestStatusNotOK) { + Errors err; + std::unique_ptr params = CreateTestCreateParams(); + // Fake a grpc create response. + containerd::services::sandbox::v1::ControllerCreateResponse response; + response.set_sandbox_id(DUMMY_SANDBOX_ID); + EXPECT_CALL(GetStub(), Create).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->Create(DUMMY_SANDBOX_ID, *params, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} + +/************* Unit tests for Start *************/ +TEST_F(ControllerSandboxerTest, StartTestSucceed) { + Errors err; + sandbox::ControllerSandboxInfo sandboxInfo; + std::unique_ptr response = CreateTestGrpcStartResponse(); + EXPECT_CALL(GetStub(), Start).Times(1).WillOnce(testing::DoAll(testing::SetArgPointee<2>(*response), testing::Return(grpc::Status::OK))); + EXPECT_TRUE(m_sandboxerClient->Start(DUMMY_SANDBOX_ID, sandboxInfo, err)); + EXPECT_TRUE(err.Empty()); + EXPECT_EQ(sandboxInfo.id, DUMMY_SANDBOX_ID); + EXPECT_EQ(sandboxInfo.pid, 1); + EXPECT_EQ(sandboxInfo.createdAt, DUMMY_CREATE_AT); + EXPECT_EQ(sandboxInfo.labels.size(), 1); + EXPECT_EQ(sandboxInfo.labels["label1"], "value1"); +} + +TEST_F(ControllerSandboxerTest, StartTestStatusNotOK) { + Errors err; + sandbox::ControllerSandboxInfo sandboxInfo; + EXPECT_CALL(GetStub(), Start).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->Start(DUMMY_SANDBOX_ID, sandboxInfo, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} + +/************* Unit tests for Prepare *************/ +TEST_F(ControllerSandboxerTest, PrepareTestSucceed) { + Errors err; + std::string bundle; + std::unique_ptr params = CreateTestPrepareParams(); + // Fake a grpc prepare response. + containerd::services::sandbox::v1::PrepareResponse response; + response.set_bundle("/tmp/bundle"); + // Set response to return bundle, and return OK for stub_->Prepare(). + EXPECT_CALL(GetStub(), Prepare).Times(1).WillOnce(testing::DoAll(testing::SetArgPointee<2>(response), testing::Return(grpc::Status::OK))); + EXPECT_TRUE(m_sandboxerClient->Prepare(DUMMY_SANDBOX_ID, *params, bundle, err)); + EXPECT_TRUE(err.Empty()); + EXPECT_EQ(bundle, "/tmp/bundle"); +} + +TEST_F(ControllerSandboxerTest, PrepareTestNullSpec) { + Errors err; + std::string bundle; + std::unique_ptr params = CreateTestPrepareParams(); + params->spec = nullptr; + // Stub should not be called + EXPECT_CALL(GetStub(), Prepare).Times(0); + EXPECT_FALSE(m_sandboxerClient->Prepare(DUMMY_SANDBOX_ID, *params, bundle, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("Failed to init prepare request for sandboxer prepare request")); +} + +TEST_F(ControllerSandboxerTest, PrepareTestNullMount) { + Errors err; + std::string bundle; + std::unique_ptr params = CreateTestPrepareParams(); + params->rootfs.push_back(nullptr); + containerd::services::sandbox::v1::PrepareRequest request; + // Save request to check mount size. + EXPECT_CALL(GetStub(), Prepare).Times(1).WillOnce(testing::DoAll(testing::SaveArg<1>(&request), testing::Return(grpc::Status::OK))); + EXPECT_TRUE(m_sandboxerClient->Prepare(DUMMY_SANDBOX_ID, *params, bundle, err)); + // The nullptr pushed in params should not be counted. + EXPECT_EQ(request.rootfs_size(), 2); + EXPECT_TRUE(err.Empty()); +} + +TEST_F(ControllerSandboxerTest, PrepareTestStatusNotOK) { + Errors err; + std::string bundle; + std::unique_ptr params = CreateTestPrepareParams(); + EXPECT_CALL(GetStub(), Prepare).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->Prepare(DUMMY_SANDBOX_ID, *params, bundle, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} + +/************* Unit tests for Purge *************/ +TEST_F(ControllerSandboxerTest, PurgeTestSucceed) { + Errors err; + // Set response to return OK for stub_->Purge(). + EXPECT_CALL(GetStub(), Purge).Times(1).WillOnce(testing::Return(grpc::Status::OK)); + EXPECT_TRUE(m_sandboxerClient->Purge(DUMMY_SANDBOX_ID, DUMMY_CONTAINER_ID, DUMMY_EXEC_ID, err)); + EXPECT_TRUE(err.Empty()); +} + +TEST_F(ControllerSandboxerTest, PurgeTestStatusNotOK) { + Errors err; + EXPECT_CALL(GetStub(), Purge).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->Purge(DUMMY_SANDBOX_ID, DUMMY_CONTAINER_ID, DUMMY_EXEC_ID, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} + +/************* Unit tests for UpdateResources *************/ +TEST_F(ControllerSandboxerTest, UpdateResourcesTestSucceed) { + Errors err; + google::protobuf::Map annotations; + std::unique_ptr params = CreateTestUpdateResourcesParams(annotations); + // Set response to return OK for stub_->UpdateResources(). + EXPECT_CALL(GetStub(), UpdateResources).Times(1).WillOnce(testing::Return(grpc::Status::OK)); + EXPECT_TRUE(m_sandboxerClient->UpdateResources(DUMMY_SANDBOX_ID, *params, err)); + EXPECT_TRUE(err.Empty()); +} + +TEST_F(ControllerSandboxerTest, UpdateResourcesTestNullResources) { + Errors err; + google::protobuf::Map annotations; + std::unique_ptr params = CreateTestUpdateResourcesParams(annotations); + params->resources = nullptr; + // Stub should not be called + EXPECT_CALL(GetStub(), UpdateResources).Times(0); + EXPECT_FALSE(m_sandboxerClient->UpdateResources(DUMMY_SANDBOX_ID, *params, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("Failed to init update-resources request for sandboxer update-resources request")); +} + +TEST_F(ControllerSandboxerTest, UpdateResourcesTestStatusNotOK) { + Errors err; + google::protobuf::Map annotations; + std::unique_ptr params = CreateTestUpdateResourcesParams(annotations); + EXPECT_CALL(GetStub(), UpdateResources).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->UpdateResources(DUMMY_SANDBOX_ID, *params, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} + +/************* Unit tests for Platform *************/ +TEST_F(ControllerSandboxerTest, PlatformTestSucceed) { + Errors err; + sandbox::ControllerPlatformInfo platformInfo; + std::unique_ptr response = CreateTestPlatformResponse(); + EXPECT_CALL(GetStub(), Platform).Times(1).WillOnce(testing::DoAll(testing::SetArgPointee<2>(*response), testing::Return(grpc::Status::OK))); + EXPECT_TRUE(m_sandboxerClient->Platform(DUMMY_SANDBOX_ID, platformInfo, err)); + EXPECT_TRUE(err.Empty()); + EXPECT_EQ(platformInfo.os, "linux"); + EXPECT_EQ(platformInfo.arch, "amd64"); + EXPECT_EQ(platformInfo.variant, "ubuntu"); +} + +TEST_F(ControllerSandboxerTest, PlatformTestStatusNotOK) { + Errors err; + sandbox::ControllerPlatformInfo platformInfo; + EXPECT_CALL(GetStub(), Platform).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->Platform(DUMMY_SANDBOX_ID, platformInfo, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} + +/************* Unit tests for Stop *************/ +TEST_F(ControllerSandboxerTest, StopTestSucceed) { + Errors err; + // Set response to return OK for stub_->Stop(). + EXPECT_CALL(GetStub(), Stop).Times(1).WillOnce(testing::Return(grpc::Status::OK)); + EXPECT_TRUE(m_sandboxerClient->Stop(DUMMY_SANDBOX_ID, 0, err)); + EXPECT_TRUE(err.Empty()); +} + +TEST_F(ControllerSandboxerTest, StopTestStatusNotOK) { + Errors err; + EXPECT_CALL(GetStub(), Stop).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->Stop(DUMMY_SANDBOX_ID, 0, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} + +/************* Unit tests for Status *************/ +TEST_F(ControllerSandboxerTest, StatusTestSucceed) { + Errors err; + sandbox::ControllerSandboxStatus sandboxStatus; + std::unique_ptr response = CreateTestStatusResponse(); + EXPECT_CALL(GetStub(), Status).Times(1).WillOnce(testing::DoAll(testing::SetArgPointee<2>(*response), testing::Return(grpc::Status::OK))); + EXPECT_TRUE(m_sandboxerClient->Status(DUMMY_SANDBOX_ID, false, sandboxStatus, err)); + EXPECT_TRUE(err.Empty()); + EXPECT_EQ(sandboxStatus.id, DUMMY_SANDBOX_ID); + EXPECT_EQ(sandboxStatus.state, "running"); + EXPECT_EQ(sandboxStatus.pid, 1); + EXPECT_EQ(sandboxStatus.taskAddress, DUMMY_TASK_ADDRESS); + EXPECT_EQ(sandboxStatus.createdAt, DUMMY_CREATE_AT); + EXPECT_EQ(sandboxStatus.exitedAt, DUMMY_CREATE_AT); + EXPECT_EQ(sandboxStatus.info.size(), 1); + EXPECT_EQ(sandboxStatus.info["info1"], "value1"); + EXPECT_EQ(sandboxStatus.extra, "{extra: test}"); +} + +TEST_F(ControllerSandboxerTest, StatusTestStatusNotOK) { + Errors err; + sandbox::ControllerSandboxStatus sandboxStatus; + EXPECT_CALL(GetStub(), Status).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->Status(DUMMY_SANDBOX_ID, false, sandboxStatus, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} + +/************* Unit tests for Shutdown *************/ +TEST_F(ControllerSandboxerTest, ShutdownTestSucceed) { + Errors err; + // Set response to return OK for stub_->Shutdown(). + EXPECT_CALL(GetStub(), Shutdown).Times(1).WillOnce(testing::Return(grpc::Status::OK)); + EXPECT_TRUE(m_sandboxerClient->Shutdown(DUMMY_SANDBOX_ID, err)); + EXPECT_TRUE(err.Empty()); +} + +TEST_F(ControllerSandboxerTest, ShutdownTestStatusNotOK) { + Errors err; + EXPECT_CALL(GetStub(), Shutdown).Times(1).WillOnce(testing::Return(grpc::Status(grpc::StatusCode::ABORTED, "gRPC Abort"))); + EXPECT_FALSE(m_sandboxerClient->Shutdown(DUMMY_SANDBOX_ID, err)); + EXPECT_THAT(err.GetCMessage(), testing::HasSubstr("gRPC Abort")); +} -- Gitee