From 7be59a7c677cf4d1205c7b9816f0f252c47afadc Mon Sep 17 00:00:00 2001 From: Grooooot Date: Fri, 6 Mar 2020 14:39:47 +0800 Subject: [PATCH] iSulad: sync openeuler at 3.6 Signed-off-by: Grooooot --- cmake/checker.cmake | 8 + cmake/options.cmake | 2 +- iSulad.spec | 15 +- src/CMakeLists.txt | 19 +- src/api/services/containers/container.proto | 9 +- src/cmd/CMakeLists.txt | 4 + src/cmd/commander.c | 17 + src/cmd/commander.h | 10 + src/cmd/isula/arguments.c | 3 + src/cmd/isula/arguments.h | 25 +- src/cmd/isula/base/create.c | 163 ++- src/cmd/isula/base/create.h | 140 ++- src/cmd/isula/base/kill.h | 9 + src/cmd/isula/base/rename.h | 8 + src/cmd/isula/base/restart.h | 8 + src/cmd/isula/base/rm.h | 10 +- src/cmd/isula/base/run.c | 2 +- src/cmd/isula/base/run.h | 10 +- src/cmd/isula/base/start.h | 9 + src/cmd/isula/base/stop.h | 10 +- src/cmd/isula/commands.h | 9 + src/cmd/isula/extend/events.c | 126 +- src/cmd/isula/extend/events.h | 12 +- src/cmd/isula/extend/export.h | 8 + src/cmd/isula/extend/pause.h | 8 + src/cmd/isula/extend/resume.h | 8 + src/cmd/isula/extend/stats.h | 10 +- src/cmd/isula/extend/update.h | 26 +- src/cmd/isula/images/images.h | 8 + src/cmd/isula/images/load.h | 10 +- src/cmd/isula/images/login.h | 10 +- src/cmd/isula/images/logout.h | 8 + src/cmd/isula/images/pull.h | 8 + src/cmd/isula/images/rmi.h | 8 + src/cmd/isula/information/health.h | 8 + src/cmd/isula/information/info.h | 8 + src/cmd/isula/information/inspect.h | 10 +- src/cmd/isula/information/logs.h | 11 +- src/cmd/isula/information/ps.h | 14 +- src/cmd/isula/information/top.h | 8 + src/cmd/isula/information/version.h | 8 + src/cmd/isula/information/wait.h | 8 + src/cmd/isula/main.c | 5 + src/cmd/isulad-shim/CMakeLists.txt | 12 + src/cmd/isulad-shim/common.c | 301 +++++ src/cmd/isulad-shim/common.h | 72 ++ src/cmd/isulad-shim/main.c | 162 +++ src/cmd/isulad-shim/process.c | 1018 +++++++++++++++ src/cmd/isulad-shim/process.h | 100 ++ src/cmd/isulad/arguments.c | 1 + src/cmd/isulad/commands.h | 4 +- src/cmd/isulad/main.c | 83 ++ src/config/isulad_config.c | 30 +- src/config/isulad_config.h | 3 + src/connect/client/grpc/client_base.h | 30 +- .../client/grpc/grpc_containers_client.cc | 51 +- .../client/grpc/grpc_isula_image_client.cc | 22 + .../client/rest/rest_containers_client.c | 30 +- src/connect/client/rest/rest_images_client.c | 8 +- .../service/grpc/grpc_containers_service.cc | 46 +- .../service/grpc/runtime_runtime_service.cc | 2 +- .../service/rest/rest_containers_service.c | 140 +-- .../service/rest/rest_images_service.c | 42 +- .../service/rest/rest_service_common.h | 2 + src/constants.h | 2 + src/container_def.c | 24 + src/container_def.h | 62 +- src/contrib/config/config.json | 14 +- src/contrib/config/daemon.json | 1 + .../config/systemcontainer_config.json | 14 +- src/cutils/utils.c | 1 - src/cutils/utils_file.c | 10 +- src/cutils/utils_file.h | 6 +- src/cutils/utils_string.c | 60 +- src/cutils/utils_string.h | 4 + src/cutils/utils_verify.c | 4 +- src/http/CMakeLists.txt | 2 +- src/http/rest_common.c | 8 +- src/http/rest_common.h | 9 +- src/image/embedded/lim.c | 6 - src/image/image.c | 110 +- src/image/image.h | 1 - src/image/oci/isula_image_fs_info.c | 2 +- src/image/oci/isula_image_pull.c | 2 +- src/image/oci/isula_image_rmi.c | 2 +- src/image/oci/isula_image_status.c | 2 +- src/image/oci/isula_images_list.c | 2 +- src/image/oci/isula_login.c | 2 +- src/image/oci/isula_rootfs_mount.c | 2 +- src/image/oci/isula_rootfs_remove.c | 2 +- src/image/oci/isula_rootfs_umount.c | 19 +- src/image/oci/oci_config_merge.c | 45 +- src/json/oci_runtime_hooks.h | 8 + .../schema/schema/container/config-v2.json | 15 + .../container/get-runtime-response.json | 15 + src/json/schema/schema/container/inspect.json | 12 + src/json/schema/schema/defs.json | 19 + src/json/schema/schema/host-config.json | 3 + .../schema/schema/isulad-daemon-configs.json | 43 +- .../schema/shim/client/process-state.json | 193 +++ src/libisula.h | 3 + src/libisulad.c | 26 +- src/libisulad.h | 11 +- src/namespace.c | 23 +- src/namespace.h | 19 + src/pack_config.c | 275 +++-- src/runtime/CMakeLists.txt | 3 + src/runtime/isula/CMakeLists.txt | 7 + src/runtime/isula/isula_rt_ops.c | 1088 +++++++++++++++++ src/runtime/isula/isula_rt_ops.h | 52 + src/runtime/lcr/lcr_rt_ops.c | 102 +- src/runtime/runtime.c | 23 +- src/runtime/runtime.h | 8 + src/services/callback.h | 3 + src/services/cri/cri_container.cc | 56 +- src/services/cri/cri_helpers.cc | 4 + src/services/cri/cri_helpers.h | 4 + src/services/cri/cri_runtime_service.h | 17 +- src/services/cri/cri_sandbox.cc | 29 +- src/services/cri/cri_services.h | 3 +- src/services/execution/events/collector.c | 549 +++++++-- src/services/execution/events/collector.h | 13 +- .../execution/events/events_handler.c | 18 +- src/services/execution/execute/execution.c | 135 +- .../execution/execute/execution_create.c | 163 ++- .../execution/execute/execution_create.h | 2 + .../execution/execute/execution_extend.c | 11 +- .../execution/execute/execution_information.c | 23 + .../execution/execute/execution_network.c | 72 +- .../execution/execute/execution_network.h | 3 +- .../execution/execute/execution_stream.c | 185 ++- .../execution/manager/container_unix.c | 52 +- .../execution/manager/container_unix.h | 2 + src/services/execution/manager/health_check.c | 2 +- src/services/execution/manager/monitord.h | 13 +- src/services/execution/manager/restore.c | 1 + src/services/execution/manager/supervisor.c | 2 +- src/services/execution/spec/selinux_label.c | 1076 ++++++++++++++++ src/services/execution/spec/selinux_label.h | 38 + src/services/execution/spec/specs.c | 391 +++++- src/services/execution/spec/specs.h | 13 +- src/services/execution/spec/specs_extend.c | 10 +- src/services/execution/spec/specs_mount.c | 351 +++++- src/services/execution/spec/specs_security.c | 120 +- src/services/execution/spec/specs_security.h | 6 +- src/services/execution/spec/sysinfo.h | 8 + src/services/execution/spec/verify.c | 62 +- src/services/execution/spec/verify.h | 8 + .../graphdriver/devmapper/driver_devmapper.c | 7 +- src/services/image/image_cb.c | 26 +- src/types_def.c | 14 +- src/types_def.h | 2 - test/CMakeLists.txt | 37 + test/cmd/CMakeLists.txt | 4 + test/cmd/isula/CMakeLists.txt | 4 + test/cmd/isula/extend/CMakeLists.txt | 4 + test/cmd/isula/extend/pause/CMakeLists.txt | 55 + test/cmd/isula/extend/pause/pause_llt.cc | 84 ++ test/cmd/isula/extend/resume/CMakeLists.txt | 56 + test/cmd/isula/extend/resume/resume_llt.cc | 84 ++ test/cmd/isula/infomation/CMakeLists.txt | 4 + test/cmd/isula/infomation/info/CMakeLists.txt | 55 + test/cmd/isula/infomation/info/info_llt.cc | 158 +++ test/cmd/isula/infomation/ps/CMakeLists.txt | 54 + test/cmd/isula/infomation/ps/ps_llt.cc | 224 ++++ test/cmd/isulad-shim/CMakeLists.txt | 22 + test/cmd/isulad-shim/isulad-shim_llt.cc | 122 ++ .../cutils/utils_convert/utils_convert_llt.cc | 2 +- test/cutils/utils_string/utils_string_llt.cc | 49 + .../image/oci/oci_config_merge/CMakeLists.txt | 14 +- .../oci_config_merge/oci_runtime_spec.json | 2 +- test/mocks/collector_mock.cc | 52 + test/mocks/collector_mock.h | 34 + test/mocks/container_state_mock.cc | 86 ++ test/mocks/container_state_mock.h | 36 + test/mocks/container_unix_mock.cc | 78 ++ test/mocks/container_unix_mock.h | 35 + test/mocks/containers_gc_mock.cc | 33 + test/mocks/containers_gc_mock.h | 29 + test/mocks/containers_store_mock.cc | 132 ++ test/mocks/containers_store_mock.h | 42 + test/mocks/driver_mock.cc | 25 + test/mocks/driver_mock.h | 27 + test/mocks/driver_overlay2_mock.cc | 49 + test/mocks/driver_overlay2_mock.h | 32 + test/mocks/engine_mock.cc | 33 + test/mocks/engine_mock.h | 30 + test/mocks/grpc_client_mock.cc | 34 + test/mocks/grpc_client_mock.h | 30 + test/mocks/health_check_mock.cc | 33 + test/mocks/health_check_mock.h | 29 + test/mocks/image_mock.cc | 57 + test/mocks/image_mock.h | 33 + test/mocks/isulad_config_mock.cc | 130 ++ test/mocks/isulad_config_mock.h | 41 + test/mocks/namespace_mock.cc | 49 + test/mocks/namespace_mock.h | 32 + test/mocks/restartmanager_mock.cc | 25 + test/mocks/restartmanager_mock.h | 28 + test/mocks/runtime_mock.cc | 74 ++ test/mocks/runtime_mock.h | 35 + test/mocks/selinux_label_mock.cc | 81 ++ test/mocks/selinux_label_mock.h | 38 + test/mocks/selinux_mock.cc | 33 + test/mocks/selinux_mock.h | 31 + test/mocks/specs_mock.cc | 49 + test/mocks/specs_mock.h | 31 + test/mocks/syscall_mock.cc | 33 + test/mocks/syscall_mock.h | 31 + test/mocks/sysinfo_mock.cc | 63 + test/mocks/sysinfo_mock.h | 33 + test/mocks/verify_mock.cc | 33 + test/mocks/verify_mock.h | 29 + test/runtime/CMakeLists.txt | 4 + test/runtime/isula/CMakeLists.txt | 67 + test/runtime/isula/isula_rt_ops_llt.cc | 132 ++ test/runtime/lcr/CMakeLists.txt | 66 + test/runtime/lcr/lcr_rt_ops_llt.cc | 595 +++++++++ test/runtime/lcr/pid.file | 1 + test/services/CMakeLists.txt | 4 + test/services/execution/CMakeLists.txt | 4 + .../services/execution/execute/CMakeLists.txt | 3 + .../execute/execution_extend/CMakeLists.txt | 82 ++ .../execution_extend/execution_extend_llt.cc | 246 ++++ test/services/execution/spec/CMakeLists.txt | 79 ++ .../execution/spec/selinux_label_llt.cc | 237 ++++ .../execution/spec/selinux_label_mock_llt.cc | 68 ++ test/services/graphdriver/CMakeLists.txt | 3 + .../graphdriver/driver/CMakeLists.txt | 48 + .../services/graphdriver/driver/driver_llt.cc | 162 +++ test/specs/CMakeLists.txt | 4 + test/specs/specs/CMakeLists.txt | 84 ++ test/specs/specs/hostconfig.json | 6 + test/specs/specs/oci_runtime_spec.json | 741 +++++++++++ test/specs/specs/specs_llt.cc | 337 +++++ test/specs/specs_extend/CMakeLists.txt | 82 ++ test/specs/specs_extend/hooks.json | 38 + test/specs/specs_extend/hostconfig.json | 6 + test/specs/specs_extend/oci_runtime_spec.json | 741 +++++++++++ test/specs/specs_extend/specs_extend_llt.cc | 288 +++++ 240 files changed, 15001 insertions(+), 868 deletions(-) create mode 100644 src/cmd/isulad-shim/CMakeLists.txt create mode 100644 src/cmd/isulad-shim/common.c create mode 100644 src/cmd/isulad-shim/common.h create mode 100644 src/cmd/isulad-shim/main.c create mode 100644 src/cmd/isulad-shim/process.c create mode 100644 src/cmd/isulad-shim/process.h create mode 100644 src/json/schema/schema/container/get-runtime-response.json create mode 100644 src/json/schema/schema/shim/client/process-state.json create mode 100644 src/runtime/isula/CMakeLists.txt create mode 100644 src/runtime/isula/isula_rt_ops.c create mode 100644 src/runtime/isula/isula_rt_ops.h create mode 100644 src/services/execution/spec/selinux_label.c create mode 100644 src/services/execution/spec/selinux_label.h create mode 100644 test/cmd/CMakeLists.txt create mode 100644 test/cmd/isula/CMakeLists.txt create mode 100644 test/cmd/isula/extend/CMakeLists.txt create mode 100644 test/cmd/isula/extend/pause/CMakeLists.txt create mode 100644 test/cmd/isula/extend/pause/pause_llt.cc create mode 100644 test/cmd/isula/extend/resume/CMakeLists.txt create mode 100644 test/cmd/isula/extend/resume/resume_llt.cc create mode 100644 test/cmd/isula/infomation/CMakeLists.txt create mode 100644 test/cmd/isula/infomation/info/CMakeLists.txt create mode 100644 test/cmd/isula/infomation/info/info_llt.cc create mode 100644 test/cmd/isula/infomation/ps/CMakeLists.txt create mode 100644 test/cmd/isula/infomation/ps/ps_llt.cc create mode 100644 test/cmd/isulad-shim/CMakeLists.txt create mode 100644 test/cmd/isulad-shim/isulad-shim_llt.cc create mode 100644 test/mocks/collector_mock.cc create mode 100644 test/mocks/collector_mock.h create mode 100644 test/mocks/container_state_mock.cc create mode 100644 test/mocks/container_state_mock.h create mode 100644 test/mocks/container_unix_mock.cc create mode 100644 test/mocks/container_unix_mock.h create mode 100644 test/mocks/containers_gc_mock.cc create mode 100644 test/mocks/containers_gc_mock.h create mode 100644 test/mocks/containers_store_mock.cc create mode 100644 test/mocks/containers_store_mock.h create mode 100644 test/mocks/driver_mock.cc create mode 100644 test/mocks/driver_mock.h create mode 100644 test/mocks/driver_overlay2_mock.cc create mode 100644 test/mocks/driver_overlay2_mock.h create mode 100644 test/mocks/engine_mock.cc create mode 100644 test/mocks/engine_mock.h create mode 100644 test/mocks/grpc_client_mock.cc create mode 100644 test/mocks/grpc_client_mock.h create mode 100644 test/mocks/health_check_mock.cc create mode 100644 test/mocks/health_check_mock.h create mode 100644 test/mocks/image_mock.cc create mode 100644 test/mocks/image_mock.h create mode 100644 test/mocks/isulad_config_mock.cc create mode 100644 test/mocks/isulad_config_mock.h create mode 100644 test/mocks/namespace_mock.cc create mode 100644 test/mocks/namespace_mock.h create mode 100644 test/mocks/restartmanager_mock.cc create mode 100644 test/mocks/restartmanager_mock.h create mode 100644 test/mocks/runtime_mock.cc create mode 100644 test/mocks/runtime_mock.h create mode 100644 test/mocks/selinux_label_mock.cc create mode 100644 test/mocks/selinux_label_mock.h create mode 100644 test/mocks/selinux_mock.cc create mode 100644 test/mocks/selinux_mock.h create mode 100644 test/mocks/specs_mock.cc create mode 100644 test/mocks/specs_mock.h create mode 100644 test/mocks/syscall_mock.cc create mode 100644 test/mocks/syscall_mock.h create mode 100644 test/mocks/sysinfo_mock.cc create mode 100644 test/mocks/sysinfo_mock.h create mode 100644 test/mocks/verify_mock.cc create mode 100644 test/mocks/verify_mock.h create mode 100644 test/runtime/CMakeLists.txt create mode 100644 test/runtime/isula/CMakeLists.txt create mode 100644 test/runtime/isula/isula_rt_ops_llt.cc create mode 100644 test/runtime/lcr/CMakeLists.txt create mode 100644 test/runtime/lcr/lcr_rt_ops_llt.cc create mode 100644 test/runtime/lcr/pid.file create mode 100644 test/services/CMakeLists.txt create mode 100644 test/services/execution/CMakeLists.txt create mode 100644 test/services/execution/execute/CMakeLists.txt create mode 100644 test/services/execution/execute/execution_extend/CMakeLists.txt create mode 100644 test/services/execution/execute/execution_extend/execution_extend_llt.cc create mode 100644 test/services/execution/spec/CMakeLists.txt create mode 100644 test/services/execution/spec/selinux_label_llt.cc create mode 100644 test/services/execution/spec/selinux_label_mock_llt.cc create mode 100644 test/services/graphdriver/CMakeLists.txt create mode 100644 test/services/graphdriver/driver/CMakeLists.txt create mode 100644 test/services/graphdriver/driver/driver_llt.cc create mode 100644 test/specs/CMakeLists.txt create mode 100644 test/specs/specs/CMakeLists.txt create mode 100644 test/specs/specs/hostconfig.json create mode 100644 test/specs/specs/oci_runtime_spec.json create mode 100644 test/specs/specs/specs_llt.cc create mode 100644 test/specs/specs_extend/CMakeLists.txt create mode 100644 test/specs/specs_extend/hooks.json create mode 100644 test/specs/specs_extend/hostconfig.json create mode 100644 test/specs/specs_extend/oci_runtime_spec.json create mode 100644 test/specs/specs_extend/specs_extend_llt.cc diff --git a/cmake/checker.cmake b/cmake/checker.cmake index 1944d04..e10c4cf 100644 --- a/cmake/checker.cmake +++ b/cmake/checker.cmake @@ -69,6 +69,14 @@ find_library(CURL_LIBRARY curl HINTS ${PC_CURL_LIBDIR} ${PC_CURL_LIBRARY_DIRS}) _CHECK(CURL_LIBRARY "CURL_LIBRARY-NOTFOUND" "libcurl.so") +pkg_check_modules(PC_SELINUX "libselinux>=2.0") +find_path(SELINUX_INCLUDE_DIR "selinux/selinux.h" + HINTS ${PC_SELINUX_INCLUDEDIR} ${PC_SELINUX_INCLUDE_DIRS}) +_CHECK(SELINUX_INCLUDE_DIR "SELINUX_INCLUDE_DIR-NOTFOUND" "selinux/selinux.h") +find_library(SELINUX_LIBRARY selinux + HINTS ${PC_SELINUX_LIBDIR} ${PC_SELINUX_LIBRARY_DIRS}) +_CHECK(SELINUX_LIBRARY "SELINUX_LIBRARY-NOTFOUND" "libselinux.so") + if (OPENSSL_VERIFY) find_path(OPENSSL_INCLUDE_DIR openssl/x509.h) _CHECK(OPENSSL_INCLUDE_DIR "OPENSSL_INCLUDE_DIR-NOTFOUND" "openssl/x509.h") diff --git a/cmake/options.cmake b/cmake/options.cmake index f4b0b34..0559a83 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -33,7 +33,7 @@ endif() option(VERSION "set isulad version" ON) if (VERSION STREQUAL "ON") - set(ISULAD_VERSION "1.1.11") + set(ISULAD_VERSION "1.1.12") endif() option(DEBUG "set isulad gcc option" ON) diff --git a/iSulad.spec b/iSulad.spec index 1ac5c06..a086531 100644 --- a/iSulad.spec +++ b/iSulad.spec @@ -1,5 +1,5 @@ -%global _version 1.1.11 -%global _release 20200204.221506.git50cfadfa +%global _version 1.1.12 +%global _release 20200306.143730.gitb83d1ed8 %global is_systemd 1 %global debug_package %{nil} @@ -30,18 +30,18 @@ Requires(preun): initscripts %endif BuildRequires: cmake gcc-c++ lxc lxc-devel lcr yajl yajl-devel clibcni-devel -BuildRequires: grpc grpc-devel protobuf-devel +BuildRequires: grpc grpc-plugins grpc-devel protobuf-devel BuildRequires: libcurl libcurl-devel sqlite-devel -BuildRequires: http-parser-devel libevhtp-devel libevent-devel -BuildRequires: libseccomp-devel libcap-devel libwebsockets libwebsockets-devel +BuildRequires: http-parser-devel +BuildRequires: libseccomp-devel libcap-devel libselinux-devel libwebsockets libwebsockets-devel BuildRequires: systemd-devel git python3 Requires: iSulad-img lcr lxc clibcni Requires: grpc protobuf yajl Requires: libcurl Requires: sqlite http-parser libseccomp -Requires: libcap libwebsockets -Requires: libevhtp libevent systemd +Requires: libcap libselinux libwebsockets +Requires: systemd %description This is a umbrella project for gRPC-services based Lightweight Container @@ -68,6 +68,7 @@ install -m 0640 ./conf/isulad.pc %{buildroot}/%{_libdir}/pkgconfig/ install -d $RPM_BUILD_ROOT/%{_bindir} install -m 0755 ./src/isula %{buildroot}/%{_bindir}/isula +install -m 0755 ./src/isulad-shim %{buildroot}/%{_bindir}/isulad-shim install -m 0755 ./src/isulad %{buildroot}/%{_bindir}/isulad install -d $RPM_BUILD_ROOT/%{_includedir}/isulad diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b0222d5..0c1b1db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,6 @@ list(REMOVE_DUPLICATES JSON_FILES) set(CHECKED_INCLUDE_DIRS ${STD_HEADER_CTYPE} ${STD_HEADER_SYS_PARAM} - ${LIBSECUREC_INCLUDE_DIR} ${LIBYAJL_INCLUDE_DIR} ${HTTP_PARSER_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} @@ -123,7 +122,7 @@ target_include_directories(libisula PUBLIC # set libisula FLAGS set_target_properties(libisula PROPERTIES PREFIX "") -target_link_libraries(libisula ${LIBYAJL_LIBRARY} ${LIBSECUREC_LIBRARY}) +target_link_libraries(libisula ${LIBYAJL_LIBRARY} ${SELINUX_LIBRARY}) if (GRPC_CONNECTOR) target_link_libraries(libisula -Wl,--as-needed -lstdc++ -lcrypto) @@ -143,6 +142,18 @@ target_include_directories(isula PUBLIC ${ISULA_INCS} ${SHARED_INCS}) target_link_libraries(isula libisula -lpthread) # ------ build isula finish ------- +# ------ build isulad-shim ------- +add_executable(isulad-shim + ${ISULAD_SHIM_SRCS} + ${CMAKE_BINARY_DIR}/json/shim_client_process_state.c + ${CMAKE_BINARY_DIR}/json/json_common.c + ${commonjsonsrcs} + ) +target_include_directories(isulad-shim PUBLIC ${ISULAD_SHIM_INCS} ${SHARED_INCS}) +target_link_libraries(isulad-shim ${LIBYAJL_LIBRARY} -lpthread) + +# ------ build isula-shim finish ------- + # ------ build isulad ------- add_subdirectory(services) add_subdirectory(image) @@ -201,7 +212,7 @@ target_include_directories(isulad PUBLIC ${WEBSOCKET_SERVICE_INCS} ) -target_link_libraries(isulad ${LIBYAJL_LIBRARY} ${LIBSECUREC_LIBRARY} ${SYSTEMD_LIBRARY}) +target_link_libraries(isulad ${LIBYAJL_LIBRARY} ${SYSTEMD_LIBRARY} ${SELINUX_LIBRARY}) target_link_libraries(isulad -ldl ${ZLIB_LIBRARY} -lpthread libhttpclient) if (ENABLE_EMBEDDED_IMAGE) target_link_libraries(isulad ${SQLITE3_LIBRARY}) @@ -237,5 +248,7 @@ install(TARGETS libisula LIBRARY DESTINATION ${LIB_INSTALL_DIR_DEFAULT} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) install(TARGETS isula RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) +install(TARGETS isulad-shim + RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) install(TARGETS isulad RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) diff --git a/src/api/services/containers/container.proto b/src/api/services/containers/container.proto index 871d703..c1a1beb 100644 --- a/src/api/services/containers/container.proto +++ b/src/api/services/containers/container.proto @@ -84,11 +84,10 @@ message Container_info { } message Event { - string id = 1; - EventType type = 2; - int32 pid = 3; - uint32 exit_status = 4; - google.protobuf.Timestamp timestamp = 5; + google.protobuf.Timestamp timestamp = 1; + string opt = 2; + string id = 3; + map annotations= 4; } service ContainerService { diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt index 8c18272..845cb0f 100644 --- a/src/cmd/CMakeLists.txt +++ b/src/cmd/CMakeLists.txt @@ -8,3 +8,7 @@ set(ISULA_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_ISULA_INCS} PARENT_SCOPE) add_subdirectory(isulad) set(ISULAD_SRCS ${comm_srcs} ${CMD_ISULAD_SRCS} PARENT_SCOPE) set(ISULAD_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_ISULAD_INCS} PARENT_SCOPE) + +add_subdirectory(isulad-shim) +set(ISULAD_SHIM_SRCS ${CMD_ISULAD_SHIM_SRCS} PARENT_SCOPE) +set(ISULAD_SHIM_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_ISULAD_SHIM_INCS} PARENT_SCOPE) diff --git a/src/cmd/commander.c b/src/cmd/commander.c index a133956..cfd1b18 100644 --- a/src/cmd/commander.c +++ b/src/cmd/commander.c @@ -737,6 +737,23 @@ int command_convert_memswapbytes(command_option_t *option, const char *arg) return 0; } +int command_convert_swappiness(command_option_t *option, const char *arg) +{ + if (option == NULL) { + return -1; + } + if (strcmp(arg, "-1") == 0) { + *(int64_t *)(option->data) = -1; + return 0; + } + if (util_parse_byte_size_string(arg, option->data) || (*(int64_t *)(option->data)) < 0 || + (*(int64_t *)(option->data)) > 100) { + COMMAND_ERROR("Invalid value \"%s\" for flag --%s. Valid memory swappiness range is 0-100", arg, option->large); + return EINVALIDARGS; + } + return 0; +} + size_t ulimit_array_len(host_config_ulimits_element **default_ulimit) { size_t len = 0; diff --git a/src/cmd/commander.h b/src/cmd/commander.h index 775456e..a7b13de 100644 --- a/src/cmd/commander.h +++ b/src/cmd/commander.h @@ -21,6 +21,10 @@ #include "host_config.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifndef COMMANDER_MAX_OPTIONS #define COMMANDER_MAX_OPTIONS 64 #endif @@ -112,5 +116,11 @@ int check_default_ulimit_type(const char *type); void free_default_ulimit(host_config_ulimits_element **default_ulimit); +int command_convert_swappiness(command_option_t *option, const char *arg); + +#ifdef __cplusplus +} +#endif + #endif /* COMMANDER_H */ diff --git a/src/cmd/isula/arguments.c b/src/cmd/isula/arguments.c index 335c25e..853239f 100644 --- a/src/cmd/isula/arguments.c +++ b/src/cmd/isula/arguments.c @@ -135,6 +135,9 @@ int client_arguments_init(struct client_arguments *args) return -1; } + // default swappiness should be set to -1 + args->cr.swappiness = -1; + return 0; } diff --git a/src/cmd/isula/arguments.h b/src/cmd/isula/arguments.h index 4ecc5b6..fcf57ae 100644 --- a/src/cmd/isula/arguments.h +++ b/src/cmd/isula/arguments.h @@ -26,6 +26,10 @@ #include "json_common.h" #include "isula_connect.h" +#ifdef __cplusplus +extern "C" { +#endif + /* max arguments can be specify in client */ #define MAX_CLIENT_ARGS 1000 @@ -39,6 +43,12 @@ struct custom_configs { /* environment variables file */ char **env_file; + /* label */ + char **label; + + /* label file */ + char **label_file; + /* hugepage limits */ char **hugepage_limits; @@ -202,6 +212,7 @@ struct args_cgroup_resources { int64_t memory_swap; int64_t memory_reservation; int64_t kernel_memory_limit; + int64_t swappiness; }; struct client_arguments { @@ -322,15 +333,15 @@ struct client_arguments { { CMD_OPT_TYPE_STRING_DUP, false, "host", 'H', &(cmdargs).socket, \ "Daemon socket(s) to connect to", command_valid_socket }, \ { CMD_OPT_TYPE_BOOL, false, "tls", 0, &(cmdargs).tls, \ - "Use TLS; implied by --tlsverify", NULL}, \ + "Use TLS; implied by --tlsverify", NULL}, \ { CMD_OPT_TYPE_BOOL, false, "tlsverify", 0, &(cmdargs).tls_verify, \ - "Use TLS and verify the remote", NULL}, \ + "Use TLS and verify the remote", NULL}, \ { CMD_OPT_TYPE_STRING_DUP, false, "tlscacert", 0, &(cmdargs).ca_file, \ - "Trust certs signed only by this CA (default \"/root/.iSulad/ca.pem\")", NULL }, \ + "Trust certs signed only by this CA (default \"/root/.iSulad/ca.pem\")", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "tlscert", 0, &(cmdargs).cert_file, \ - "Path to TLS certificate file (default \"/root/.iSulad/cert.pem\")", NULL }, \ + "Path to TLS certificate file (default \"/root/.iSulad/cert.pem\")", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "tlskey", 0, &(cmdargs).key_file, \ - "Path to TLS key file (default \"/root/.iSulad/key.pem\")", NULL }, \ + "Path to TLS key file (default \"/root/.iSulad/key.pem\")", NULL }, \ { CMD_OPT_TYPE_STRING, false, "help", 0, NULL, "Print usage", NULL } #define VERSION_OPTIONS(cmdargs) \ @@ -350,5 +361,9 @@ extern void client_print_error(uint32_t cc, uint32_t server_errono, const char * extern client_connect_config_t get_connect_config(const struct client_arguments *args); +#ifdef __cplusplus +} +#endif + #endif /* __ISULA_ARGUMENTS_H */ diff --git a/src/cmd/isula/base/create.c b/src/cmd/isula/base/create.c index 7cc41df..0a662d6 100644 --- a/src/cmd/isula/base/create.c +++ b/src/cmd/isula/base/create.c @@ -13,6 +13,7 @@ * Description: provide container create functions ******************************************************************************/ #include +#include #include #include #include @@ -37,7 +38,7 @@ const char g_cmd_create_desc[] = "Create a new container"; const char g_cmd_create_usage[] = "create [OPTIONS] --external-rootfs=PATH|IMAGE [COMMAND] [ARG...]"; struct client_arguments g_cmd_create_args = { - .runtime = "lcr", + .runtime = "", .restart = "no", .log_file_size = "1MB", .log_file_rotate = 7, @@ -172,6 +173,8 @@ static int request_pack_host_config_cgroup(const struct client_arguments *args, /* kernel memory limit */ hostconfig->cr->kernel_memory = args->cr.kernel_memory_limit; + hostconfig->cr->swappiness = args->cr.swappiness; + request_pack_host_config_limit(args, hostconfig); return 0; @@ -414,6 +417,149 @@ out: return ret; } +static bool validate_label(const char *label) +{ + bool ret = true; + char **arr = util_string_split_n(label, '=', 2); + if (arr == NULL) { + ERROR("Failed to split label string"); + ret = false; + goto out; + } + + if (strlen(arr[0]) == 0) { + ERROR("Invalid label: %s, empty name", label); + ret = false; + goto out; + } + +out: + util_free_array(arr); + return ret; +} + +static int request_pack_custom_label(struct client_arguments *args, isula_container_config_t *conf) +{ + int ret = 0; + size_t i; + + if (args->custom_conf.label == NULL) { + return 0; + } + + for (i = 0; i < util_array_len((const char **)(args->custom_conf.label)); i++) { + if (!validate_label(args->custom_conf.label[i])) { + COMMAND_ERROR("Invalid label '%s': empty name", args->custom_conf.label[i]); + ret = -1; + goto out; + } + if (util_array_append(&conf->label, args->custom_conf.label[i]) != 0) { + COMMAND_ERROR("Failed to append custom config label list"); + ret = -1; + goto out; + } + } + util_free_array(args->custom_conf.label); + args->custom_conf.label = conf->label; /* make sure args->custom_conf.label point to valid memory. */ + conf->label_len = util_array_len((const char **)(conf->label)); + +out: + return ret; +} + +static int read_label_from_file(const char *path, size_t file_size, isula_container_config_t *conf) +{ + int ret = 0; + FILE *fp = NULL; + char *buf = NULL; + size_t len; + ssize_t num; + + if (file_size == 0) { + return 0; + } + fp = fopen(path, "re"); + if (fp == NULL) { + ERROR("Failed to open '%s'", path); + return -1; + } + __fsetlocking(fp, FSETLOCKING_BYCALLER); + num = getline(&buf, &len, fp); + while (num != -1) { + size_t len = strlen(buf); + if (len == 1) { + num = getline(&buf, &len, fp); + continue; + } + buf[len - 1] = '\0'; + if (!validate_label(buf)) { + COMMAND_ERROR("Invalid label '%s': empty name", buf); + ret = -1; + goto out; + } + if (util_array_append(&conf->label, buf) != 0) { + ERROR("Failed to append label"); + ret = -1; + goto out; + } + num = getline(&buf, &len, fp); + } + +out: + free(buf); + fclose(fp); + return ret; +} + +static int append_labels_to_conf(const char *label_file, isula_container_config_t *conf) +{ + int ret = 0; + size_t file_size; + + if (!util_file_exists(label_file)) { + COMMAND_ERROR("label file not exists: %s", label_file); + ret = -1; + goto out; + } + file_size = util_file_size(label_file); + if (file_size > REGULAR_FILE_SIZE) { + COMMAND_ERROR("label file '%s', size exceed limit: %lld", label_file, REGULAR_FILE_SIZE); + ret = -1; + goto out; + } + + if (read_label_from_file(label_file, file_size, conf) != 0) { + COMMAND_ERROR("failed to read label from file: %s", label_file); + ret = -1; + goto out; + } + +out: + return ret; +} + +static int request_pack_custom_label_file(const struct client_arguments *args, isula_container_config_t *conf) +{ + int ret = 0; + size_t i; + char **label_files = args->custom_conf.label_file; + size_t label_files_size = util_array_len((const char **)label_files); + if (label_files_size == 0) { + return 0; + } + + for (i = 0; i < label_files_size; i++) { + if (append_labels_to_conf(label_files[i], conf) != 0) { + ret = -1; + goto out; + } + } + conf->label_len = util_array_len((const char **)(conf->label)); + +out: + return ret; +} + static void request_pack_custom_user(const struct client_arguments *args, isula_container_config_t *conf) { if (args->custom_conf.user != NULL) { @@ -577,17 +723,27 @@ static int request_pack_custom_conf(struct client_arguments *args, isula_contain return -1; } - /* Make sure --env has higher priority than --env-file */ + /* make sure --env has higher priority than --env-file */ if (request_pack_custom_env(args, conf) != 0) { return -1; } + /* append labels from label file */ + if (request_pack_custom_label_file(args, conf) != 0) { + return -1; + } + + /* make sure --label has higher priority than --label-file */ + if (request_pack_custom_label(args, conf) != 0) { + return -1; + } + /* user and group */ request_pack_custom_user(args, conf); request_pack_custom_hostname(args, conf); - /* alldevices */ + /* all devices */ request_pack_custom_all_devices(args, conf); /* system container */ @@ -1225,6 +1381,7 @@ out: return ret; } + int callback_annotation(command_option_t *option, const char *value) { struct client_arguments *args = (struct client_arguments *)option->data; diff --git a/src/cmd/isula/base/create.h b/src/cmd/isula/base/create.h index 87ad1c1..bbfa53c 100644 --- a/src/cmd/isula/base/create.h +++ b/src/cmd/isula/base/create.h @@ -17,137 +17,147 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define CREATE_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_CALLBACK, false, "accel", 0, &(cmdargs).custom_conf.accel, \ "Accelerator bindings (format: [=][@[,]])", \ command_append_array }, \ { CMD_OPT_TYPE_BOOL, false, "read-only", 0, &(cmdargs).custom_conf.readonly, \ - "Make container rootfs readonly", NULL }, \ + "Make container rootfs readonly", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "cap-add", 0, &(cmdargs).custom_conf.cap_adds, \ - "Add Linux capabilities ('ALL' to add all capabilities)", command_append_array }, \ + "Add Linux capabilities ('ALL' to add all capabilities)", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "cap-drop", 0, &(cmdargs).custom_conf.cap_drops, \ - "Drop Linux capabilities ('ALL' to drop all capabilities)", command_append_array }, \ + "Drop Linux capabilities ('ALL' to drop all capabilities)", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "cpu-shares", 0, &(cmdargs).cr.cpu_shares, \ - "CPU shares (relative weight)", command_convert_llong }, \ + "CPU shares (relative weight)", command_convert_llong }, \ { CMD_OPT_TYPE_CALLBACK, false, "cpu-period", 0, &(cmdargs).cr.cpu_period, \ - "Limit CPU CFS (Completely Fair Scheduler) period", command_convert_llong }, \ + "Limit CPU CFS (Completely Fair Scheduler) period", command_convert_llong }, \ { CMD_OPT_TYPE_CALLBACK, false, "cpu-quota", 0, &(cmdargs).cr.cpu_quota, \ - "Limit CPU CFS (Completely Fair Scheduler) quota", command_convert_llong }, \ + "Limit CPU CFS (Completely Fair Scheduler) quota", command_convert_llong }, \ { CMD_OPT_TYPE_STRING, false, "cpuset-cpus", 0, &(cmdargs).cr.cpuset_cpus, \ - "CPUs in which to allow execution (e.g. 0-3, 0,1)", NULL }, \ + "CPUs in which to allow execution (e.g. 0-3, 0,1)", NULL }, \ { CMD_OPT_TYPE_STRING, false, "cpuset-mems", 0, &(cmdargs).cr.cpuset_mems, \ - "MEMs in which to allow execution (0-3, 0,1)", NULL }, \ + "MEMs in which to allow execution (0-3, 0,1)", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "device-read-bps", 0, &(cmdargs).custom_conf.blkio_throttle_read_bps_device, \ - "Limit read rate (bytes per second) from a device (default [])", command_append_array }, \ + "Limit read rate (bytes per second) from a device (default [])", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "device-write-bps", 0, &(cmdargs).custom_conf.blkio_throttle_write_bps_device, \ - "Limit write rate (bytes per second) to a device (default [])", command_append_array }, \ + "Limit write rate (bytes per second) to a device (default [])", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "oom-score-adj", 0, &(cmdargs).cr.oom_score_adj, \ - "Tune host's OOM preferences (-1000 to 1000)", command_convert_llong }, \ + "Tune host's OOM preferences (-1000 to 1000)", command_convert_llong }, \ { CMD_OPT_TYPE_CALLBACK, false, "device", 0, &(cmdargs).custom_conf.devices, \ - "Add a host device to the container", command_append_array }, \ + "Add a host device to the container", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "env", 'e', &(cmdargs).custom_conf.env, \ - "Set environment variables", command_append_array }, \ + "Set environment variables", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "env-file", 0, &(cmdargs).custom_conf.env_file, \ - "Read in a file of environment variables", command_append_array }, \ + "Read in a file of environment variables", command_append_array }, \ + { CMD_OPT_TYPE_CALLBACK, false, "label", 'l', &(cmdargs).custom_conf.label, \ + "Set metadata on container (default [])", command_append_array }, \ + { CMD_OPT_TYPE_CALLBACK, false, "label-file", 0, &(cmdargs).custom_conf.label_file, \ + "Read in a line delimited file of labels (default [])", command_append_array }, \ { CMD_OPT_TYPE_STRING_DUP, false, "entrypoint", 0, &(cmdargs).custom_conf.entrypoint, \ - "Entrypoint to run when starting the container", NULL }, \ + "Entrypoint to run when starting the container", NULL }, \ { CMD_OPT_TYPE_STRING, false, "external-rootfs", 0, &(cmdargs).external_rootfs, \ - "Specify the custom rootfs that is not managed by isulad for the container, directory or block device", NULL }, \ + "Specify the custom rootfs that is not managed by isulad for the container, directory or block device", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "files-limit", 0, &(cmdargs).custom_conf.files_limit, \ - "Tune container files limit (set -1 for unlimited)", command_convert_llong }, \ + "Tune container files limit (set -1 for unlimited)", command_convert_llong }, \ { CMD_OPT_TYPE_STRING_DUP, false, "hook-spec", 0, &(cmdargs).custom_conf.hook_spec, \ - "File containing hook definition(prestart, poststart, poststop)", NULL }, \ + "File containing hook definition(prestart, poststart, poststop)", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "hostname", 'h', &(cmdargs).custom_conf.hostname, \ - "Container host name", NULL }, \ + "Container host name", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "add-host", 0, &(cmdargs).custom_conf.extra_hosts, \ - "Add a custom host-to-IP mapping (host:ip)", command_append_array }, \ + "Add a custom host-to-IP mapping (host:ip)", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "dns", 0, &(cmdargs).custom_conf.dns, \ - "Set custom DNS servers", command_append_array }, \ + "Set custom DNS servers", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "dns-opt", 0, &(cmdargs).custom_conf.dns_options, \ - "Set DNS options", command_append_array }, \ + "Set DNS options", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "dns-search", 0, &(cmdargs).custom_conf.dns_search, \ - "Set custom DNS search domains", command_append_array }, \ + "Set custom DNS search domains", command_append_array }, \ { CMD_OPT_TYPE_STRING, false, "user-remap", 0, &(cmdargs).custom_conf.user_remap, \ - "Set user remap for container", NULL }, \ + "Set user remap for container", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "ipc", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_IPC], \ - "IPC namespace to use", NULL }, \ + "IPC namespace to use", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "shm-size", 0, &(cmdargs).custom_conf.shm_size, \ - "Size of /dev/shm, default value is 64MB", command_convert_membytes }, \ + "Size of /dev/shm, default value is 64MB", command_convert_membytes }, \ { CMD_OPT_TYPE_CALLBACK, false, "kernel-memory", 0, &(cmdargs).cr.kernel_memory_limit, \ - "Kernel memory limit", command_convert_membytes }, \ + "Kernel memory limit", command_convert_membytes }, \ { CMD_OPT_TYPE_CALLBACK, false, "hugetlb-limit", 0, &(cmdargs).custom_conf.hugepage_limits, \ - "Huge page limit (format: [size:], e.g. --hugetlb-limit 2MB:32MB)", command_append_array }, \ + "Huge page limit (format: [size:], e.g. --hugetlb-limit 2MB:32MB)", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "log-opt", 0, &(cmdargs), \ - "Container log options, value formate: key=value", callback_log_opt }, \ + "Container log options, value formate: key=value", callback_log_opt }, \ { CMD_OPT_TYPE_CALLBACK, false, "memory", 'm', &(cmdargs).cr.memory_limit, \ - "Memory limit", command_convert_membytes }, \ + "Memory limit", command_convert_membytes }, \ { CMD_OPT_TYPE_CALLBACK, false, "memory-reservation", 0, &(cmdargs).cr.memory_reservation, \ - "Memory soft limit", command_convert_membytes }, \ + "Memory soft limit", command_convert_membytes }, \ { CMD_OPT_TYPE_CALLBACK, false, "memory-swap", 0, &(cmdargs).cr.memory_swap, \ - "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", command_convert_memswapbytes }, \ + "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", command_convert_memswapbytes }, \ + { CMD_OPT_TYPE_CALLBACK, false, "memory-swappiness", 0, &(cmdargs).cr.swappiness, \ + "Tune container memory swappiness (0 to 100) (default -1)", command_convert_swappiness }, \ { CMD_OPT_TYPE_CALLBACK, false, "mount", 0, &(cmdargs).custom_conf.mounts, \ - "Attach a filesystem mount to the service", command_append_array }, \ + "Attach a filesystem mount to the service", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "group-add", 0, &(cmdargs).custom_conf.group_add, \ - "Add additional groups to join", command_append_array }, \ + "Add additional groups to join", command_append_array }, \ { CMD_OPT_TYPE_STRING_DUP, false, "name", 'n', &(cmdargs).name, "Name of the container", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "net", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_NET], \ - "Connect a container to a network", NULL }, \ + "Connect a container to a network", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "pid", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_PID], \ - "PID namespace to use", NULL }, \ + "PID namespace to use", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "pids-limit", 0, &(cmdargs).custom_conf.pids_limit, \ - "Tune container pids limit (set -1 for unlimited)", command_convert_llong }, \ + "Tune container pids limit (set -1 for unlimited)", command_convert_llong }, \ { CMD_OPT_TYPE_BOOL, false, "privileged", 0, &(cmdargs).custom_conf.privileged, \ - "Give extended privileges to this container", NULL }, \ + "Give extended privileges to this container", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "tty", 't', &(cmdargs).custom_conf.tty, "Allocate a pseudo-TTY", NULL }, \ { CMD_OPT_TYPE_STRING, false, "restart", 0, &(cmdargs).restart, \ - "Restart policy to apply when a container exits(no, always, on-reboot, on-failure[:max-retries])", NULL }, \ + "Restart policy to apply when a container exits(no, always, on-reboot, on-failure[:max-retries])", NULL }, \ { CMD_OPT_TYPE_STRING, false, "host-channel", 0, &(cmdargs).host_channel, \ - "Create share memory between host and container", NULL }, \ + "Create share memory between host and container", NULL }, \ { CMD_OPT_TYPE_STRING, false, "runtime", 'R', &(cmdargs).runtime, \ - "Runtime to use for containers(default: lcr)", NULL }, \ + "Runtime to use for containers(default: lcr)", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "user", 'u', &(cmdargs).custom_conf.user, \ - "Username or UID (format: [:])", NULL }, \ + "Username or UID (format: [:])", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "uts", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_UTS], \ - "UTS namespace to use", NULL }, \ + "UTS namespace to use", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "volume", 'v', &(cmdargs).custom_conf.volumes, \ - "Bind mount a volume", command_append_array }, \ + "Bind mount a volume", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "annotation", 0, &(cmdargs), \ - "Set annotations on a container", callback_annotation }, \ + "Set annotations on a container", callback_annotation }, \ { CMD_OPT_TYPE_STRING_DUP, false, "workdir", 0, &(cmdargs).custom_conf.workdir, \ - "Working directory inside the container", NULL }, \ + "Working directory inside the container", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "system-container", 0, &(cmdargs).custom_conf.system_container, \ - "Extend some features only needed by running system container", NULL }, \ + "Extend some features only needed by running system container", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "oom-kill-disable", 0, &(cmdargs).custom_conf.oom_kill_disable, \ - "Disable OOM Killer", NULL }, \ + "Disable OOM Killer", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "security-opt", 0, &(cmdargs).custom_conf.security, \ - "Security Options (default [])", command_append_array }, \ + "Security Options (default [])", command_append_array }, \ { CMD_OPT_TYPE_CALLBACK, false, "storage-opt", 0, &(cmdargs).custom_conf.storage_opts, \ - "Storage driver options for the container", command_append_array }, \ + "Storage driver options for the container", command_append_array }, \ { CMD_OPT_TYPE_STRING_DUP, false, "health-cmd", 0, &(cmdargs).custom_conf.health_cmd, \ - "Command to run to check health", NULL }, \ + "Command to run to check health", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "sysctl", 0, &(cmdargs).custom_conf.sysctls, \ - "Sysctl options", command_append_array }, \ + "Sysctl options", command_append_array }, \ { CMD_OPT_TYPE_STRING_DUP, false, "env-target-file", 0, &(cmdargs).custom_conf.env_target_file, \ - "Export env to target file path in rootfs", NULL }, \ + "Export env to target file path in rootfs", NULL }, \ { CMD_OPT_TYPE_STRING_DUP, false, "cgroup-parent", 0, &(cmdargs).custom_conf.cgroup_parent, \ - "Optional parent cgroup for the container", NULL }, \ + "Optional parent cgroup for the container", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "health-interval", 0, &(cmdargs).custom_conf.health_interval, \ - "Time between running the check (ms|s|m|h) (default 30s)", command_convert_nanoseconds }, \ + "Time between running the check (ms|s|m|h) (default 30s)", command_convert_nanoseconds }, \ { CMD_OPT_TYPE_CALLBACK, false, "health-retries", 0, &(cmdargs).custom_conf.health_retries, \ - "Consecutive failures needed to report unhealthy (default 3)", command_convert_int }, \ + "Consecutive failures needed to report unhealthy (default 3)", command_convert_int }, \ { CMD_OPT_TYPE_CALLBACK, false, "health-timeout", 0, &(cmdargs).custom_conf.health_timeout, \ - "Maximum time to allow one check to run (ms|s|m|h) (default 30s)", command_convert_nanoseconds }, \ + "Maximum time to allow one check to run (ms|s|m|h) (default 30s)", command_convert_nanoseconds }, \ { CMD_OPT_TYPE_CALLBACK, false, "health-start-period", 0, &(cmdargs).custom_conf.health_start_period, \ - "Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) " \ - "(default 0s)", command_convert_nanoseconds }, \ + "Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) " \ + "(default 0s)", command_convert_nanoseconds }, \ { CMD_OPT_TYPE_BOOL, false, "no-healthcheck", 0, &(cmdargs).custom_conf.no_healthcheck, \ - "Disable any container-specified HEALTHCHECK", NULL }, \ + "Disable any container-specified HEALTHCHECK", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "health-exit-on-unhealthy", 0, &(cmdargs).custom_conf.exit_on_unhealthy, \ - "Kill the container when it is detected to be unhealthy", NULL }, \ + "Kill the container when it is detected to be unhealthy", NULL }, \ { CMD_OPT_TYPE_STRING, false, "ns-change-opt", 0, &(cmdargs).custom_conf.ns_change_opt, \ - "Namespaced kernel param options for system container (default [])", NULL }, \ + "Namespaced kernel param options for system container (default [])", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "ulimit", 0, &(cmdargs).custom_conf.ulimits, \ - "Ulimit options (default [])", command_append_array } + "Ulimit options (default [])", command_append_array } #define CREATE_EXTEND_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, false, "interactive", 'i', &(cmdargs).custom_conf.open_stdin, \ @@ -169,5 +179,9 @@ int callback_annotation(command_option_t *option, const char *value); int cmd_create_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_CREATE_H */ diff --git a/src/cmd/isula/base/kill.h b/src/cmd/isula/base/kill.h index 605b225..8b08786 100644 --- a/src/cmd/isula/base/kill.h +++ b/src/cmd/isula/base/kill.h @@ -18,6 +18,10 @@ #include "arguments.h" #include "wait.h" +#ifdef __cplusplus +extern "C" { +#endif + #define KILL_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_STRING, false, "signal", 's', &(cmdargs).signal, \ "Signal to send to the container (default \"SIGKILL\")", NULL } @@ -26,5 +30,10 @@ extern const char g_cmd_kill_desc[]; extern const char g_cmd_kill_usage[]; extern struct client_arguments g_cmd_kill_args; int cmd_kill_main(int argc, const char **argv); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/cmd/isula/base/rename.h b/src/cmd/isula/base/rename.h index 9f921f7..2f9c211 100644 --- a/src/cmd/isula/base/rename.h +++ b/src/cmd/isula/base/rename.h @@ -17,10 +17,18 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_rename_desc[]; extern const char g_cmd_rename_usage[]; extern struct client_arguments g_cmd_rename_args; int cmd_rename_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/cmd/isula/base/restart.h b/src/cmd/isula/base/restart.h index 1af6a22..0f1e00c 100644 --- a/src/cmd/isula/base/restart.h +++ b/src/cmd/isula/base/restart.h @@ -15,6 +15,10 @@ #ifndef __CMD_RESTART_H #define __CMD_RESTART_H +#ifdef __cplusplus +extern "C" { +#endif + #define RESTART_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_CALLBACK, false, "time", 't', &(cmdargs).time, \ "Seconds to wait for stop before killing it (default 10)", command_convert_int } @@ -24,5 +28,9 @@ extern const char g_cmd_restart_usage[]; extern struct client_arguments g_cmd_restart_args; int cmd_restart_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_RESTART_H */ diff --git a/src/cmd/isula/base/rm.h b/src/cmd/isula/base/rm.h index 5f6ee08..c89d7cf 100644 --- a/src/cmd/isula/base/rm.h +++ b/src/cmd/isula/base/rm.h @@ -17,16 +17,24 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define DELETE_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, false, "force", 'f', &(cmdargs).force, \ "Force the removal of a running container (uses SIGKILL)", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "volumes", 'v', &(cmdargs).volume, \ - "Remove the volumes associated with the container", NULL } + "Remove the volumes associated with the container", NULL } extern const char g_cmd_delete_desc[]; extern const char g_cmd_delete_usage[]; extern struct client_arguments g_cmd_delete_args; int cmd_delete_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_DELETE_H */ diff --git a/src/cmd/isula/base/run.c b/src/cmd/isula/base/run.c index a059cde..7e846ba 100644 --- a/src/cmd/isula/base/run.c +++ b/src/cmd/isula/base/run.c @@ -29,7 +29,7 @@ const char g_cmd_run_desc[] = "Run a command in a new container"; const char g_cmd_run_usage[] = "run [OPTIONS] ROOTFS|IMAGE [COMMAND] [ARG...]"; static int run_checker(struct client_arguments *args); struct client_arguments g_cmd_run_args = { - .runtime = "lcr", + .runtime = "", .restart = "no", .log_file = NULL, .log_file_size = "1MB", diff --git a/src/cmd/isula/base/run.h b/src/cmd/isula/base/run.h index e080fe3..1589a2b 100644 --- a/src/cmd/isula/base/run.h +++ b/src/cmd/isula/base/run.h @@ -19,16 +19,24 @@ #include "start.h" #include "wait.h" +#ifdef __cplusplus +extern "C" { +#endif + #define RUN_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, false, "detach", 'd', &(cmdargs).detach, \ "Run container in background and print container ID", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "rm", 0, &(cmdargs).custom_conf.auto_remove, \ - "Automatically remove the container when it exits", NULL } + "Automatically remove the container when it exits", NULL } extern const char g_cmd_run_desc[]; extern const char g_cmd_run_usage[]; extern struct client_arguments g_cmd_run_args; int cmd_run_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_RUN_H */ diff --git a/src/cmd/isula/base/start.h b/src/cmd/isula/base/start.h index b584000..69945cc 100644 --- a/src/cmd/isula/base/start.h +++ b/src/cmd/isula/base/start.h @@ -19,6 +19,10 @@ #include "commands.h" #include +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_start_desc[]; extern struct client_arguments g_cmd_start_args; @@ -28,5 +32,10 @@ void client_restore_console(bool reset_tty, const struct termios *oldtios, struc int client_start(const struct client_arguments *args, bool *reset_tty, struct termios *oldtios, struct command_fifo_config **console_fifos); int cmd_start_main(int argc, const char **argv); + +#ifdef __cplusplus +} +#endif + #endif /* __CMD_START_H */ diff --git a/src/cmd/isula/base/stop.h b/src/cmd/isula/base/stop.h index f2f1dbc..9b6fdcb 100644 --- a/src/cmd/isula/base/stop.h +++ b/src/cmd/isula/base/stop.h @@ -17,10 +17,14 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define STOP_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, false, "force", 'f', &(cmdargs).force, "Stop by force killing", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "time", 't', &(cmdargs).time, \ - "Seconds to wait for stop before killing it (default 10)", command_convert_int } + "Seconds to wait for stop before killing it (default 10)", command_convert_int } extern const char g_cmd_stop_desc[]; extern const char g_cmd_stop_usage[]; @@ -28,5 +32,9 @@ extern struct client_arguments g_cmd_stop_args; int cmd_stop_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_STOP_H */ diff --git a/src/cmd/isula/commands.h b/src/cmd/isula/commands.h index 7ed3b97..06f6cf3 100644 --- a/src/cmd/isula/commands.h +++ b/src/cmd/isula/commands.h @@ -18,6 +18,10 @@ #include "arguments.h" #include +#ifdef __cplusplus +extern "C" { +#endif + #define CLIENT_RUNDIR "/var/run/isula" // A command is described by: @@ -69,5 +73,10 @@ int commmand_default_help(const char * const program_name, const char **argv); int run_command(struct command *commands, int argc, const char **argv); + +#ifdef __cplusplus +} +#endif + #endif /* __COMMAND_H */ diff --git a/src/cmd/isula/extend/events.c b/src/cmd/isula/extend/events.c index f9bae5c..9516238 100644 --- a/src/cmd/isula/extend/events.c +++ b/src/cmd/isula/extend/events.c @@ -26,53 +26,119 @@ struct client_arguments g_cmd_events_args = { .until = NULL, }; -static const char * const g_strtype[] = { - "EXIT", "STOPPED", "STARTING", "RUNNING", "STOPPING", "ABORTING", "FREEZING", - "FROZEN", "THAWED", "OOM", "CREATE", "START", "EXEC_ADDED", "PAUSED1", -}; - -static const char *lcrsta2str(container_events_type_t sta) +static size_t calacute_annotations_msg_len(const container_events_format_t *event) { - if (sta > EVENTS_TYPE_PAUSED1) { + size_t annos_msg_len = 0; + size_t i; + + for (i = 0; i < event->annotations_len; i++) { + annos_msg_len += strlen(event->annotations[i]); + } + annos_msg_len += event->annotations_len * 2; + + return annos_msg_len; +} + +static size_t calacute_event_msg_len(const container_events_format_t *event, const char *timebuffer) +{ + size_t msg_len = 0; + // format : timestamp (container|image opt) id (annotaions) + msg_len += strlen(timebuffer) + 1 + strlen(event->opt) + 1 + strlen(event->id) + 1; + msg_len += calacute_annotations_msg_len(event); + msg_len += 1; // '\0' + + return msg_len; +} + +static int generate_annotations_msg(const container_events_format_t *event, char **anno_msg) +{ + size_t i; + size_t anno_msg_len = calacute_annotations_msg_len(event) + 1; + + if (anno_msg_len == 1) { + return 0; + } + + *anno_msg = (char *)util_common_calloc_s(anno_msg_len); + if (*anno_msg == NULL) { + ERROR("Event: Out of memory"); + return -1; + } + + (void)strcat(*anno_msg, "("); + for (i = 0; i < event->annotations_len; i++) { + (void)strcat(*anno_msg, event->annotations[i]); + if (i != event->annotations_len - 1) { + (void)strcat(*anno_msg, ", "); + } + } + (void)strcat(*anno_msg, ")"); + (*anno_msg)[anno_msg_len - 1] = '\0'; + + return 0; +} + +static char *generate_event_msg(const container_events_format_t *event, const char *timebuffer, size_t len) +{ + int nret = 0; + char *anno_msg = NULL; + char *msg = NULL; + + if (generate_annotations_msg(event, &anno_msg) != 0) { + ERROR("Event: Failed to generate annotations msg"); return NULL; } - return g_strtype[sta]; + + msg = (char *)util_common_calloc_s(len); + if (msg == NULL) { + ERROR("Event: Out of memory"); + goto err_out; + } + if (anno_msg != NULL) { + nret = snprintf(msg, len, "%s %s %s %s", timebuffer, event->opt, event->id, anno_msg); + } else { + nret = snprintf(msg, len, "%s %s %s", timebuffer, event->opt, event->id); + } + if (nret < 0 || (size_t)nret >= len) { + ERROR("Event: compose event massage failed"); + goto err_out; + } + msg[len - 1] = '\0'; + + free(anno_msg); + return msg; + +err_out: + free(anno_msg); + free(msg); + return NULL; } static void print_events_callback(const container_events_format_t *event) { char timebuffer[512] = { 0 }; + char *msg = NULL; + size_t msg_len = 0; if (event == NULL) { return; } - printf("--------------------------------------------------\n"); - printf("%-15s %s\n", "Name:", event->id); - - if (get_time_buffer(&(event->timestamp), timebuffer, sizeof(timebuffer))) { - printf("%-15s %s\n", "Time:", timebuffer); - } else { - printf("%-15s %s\n", "Time:", "-"); + if (!get_time_buffer(&(event->timestamp), timebuffer, sizeof(timebuffer))) { + (void)strcpy(timebuffer, "-"); } - if (event->has_type) { - printf("%-15s %s\n", "EventType:", lcrsta2str(event->type)); - } else { - printf("%-15s %s\n", "EventType:", "-"); + msg_len = calacute_event_msg_len(event, timebuffer); + + msg = generate_event_msg(event, timebuffer, msg_len); + if (msg == NULL) { + printf("generate event message failed\n"); + return; } - if (event->has_pid) { - printf("%-15s %u\n", "Pid:", event->pid); - } else { - printf("%-15s %s\n", "Pid:", "-"); - } + printf("%s\n", msg); - if (event->has_exit_status) { - printf("%-15s %u\n", "Exit_Status:", event->exit_status); - } else { - printf("%-15s %s\n", "Exit_Status:", "-"); - } + free(msg); } /* @@ -116,7 +182,7 @@ static int client_event(struct client_arguments *args) config = get_connect_config(args); ret = ops->container.events(&request, response, &config); - if (ret) { + if (ret != 0) { COMMAND_ERROR("Failed to get container events, %s", response->errmsg ? response->errmsg : errno_to_error_message(response->cc)); } diff --git a/src/cmd/isula/extend/events.h b/src/cmd/isula/extend/events.h index 76f4982..0943526 100644 --- a/src/cmd/isula/extend/events.h +++ b/src/cmd/isula/extend/events.h @@ -17,18 +17,26 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define EVENTS_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_STRING, false, "name", 'n', &(cmdargs).name, \ "Name of the container", NULL }, \ { CMD_OPT_TYPE_STRING, false, "since", 'S', &(cmdargs).since, \ - "Show all events created since this timestamp", NULL }, \ + "Show all events created since this timestamp", NULL }, \ { CMD_OPT_TYPE_STRING, false, "until", 'U', &(cmdargs).until, \ - "Show all events created until this timestamp", NULL } + "Show all events created until this timestamp", NULL } extern const char g_cmd_events_desc[]; extern const char g_cmd_events_usage[]; extern struct client_arguments g_cmd_events_args; int cmd_events_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_EVENT_H */ diff --git a/src/cmd/isula/extend/export.h b/src/cmd/isula/extend/export.h index 5209504..dada33f 100644 --- a/src/cmd/isula/extend/export.h +++ b/src/cmd/isula/extend/export.h @@ -17,6 +17,10 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define EXPORT_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_STRING, false, "output", 'o', &(cmdargs).file, "Write to a file", NULL } @@ -25,5 +29,9 @@ extern const char g_cmd_export_usage[]; extern struct client_arguments g_cmd_export_args; int cmd_export_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/cmd/isula/extend/pause.h b/src/cmd/isula/extend/pause.h index 8b75807..1facb0e 100644 --- a/src/cmd/isula/extend/pause.h +++ b/src/cmd/isula/extend/pause.h @@ -17,10 +17,18 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_pause_desc[]; extern const char g_cmd_pause_usage[]; extern struct client_arguments g_cmd_pause_args; int cmd_pause_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/cmd/isula/extend/resume.h b/src/cmd/isula/extend/resume.h index 655b3fe..1aff634 100644 --- a/src/cmd/isula/extend/resume.h +++ b/src/cmd/isula/extend/resume.h @@ -17,10 +17,18 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_resume_desc[]; extern const char g_cmd_resume_usage[]; extern struct client_arguments g_cmd_resume_args; int cmd_resume_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/cmd/isula/extend/stats.h b/src/cmd/isula/extend/stats.h index 2535116..5634d3b 100644 --- a/src/cmd/isula/extend/stats.h +++ b/src/cmd/isula/extend/stats.h @@ -17,16 +17,24 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define STATUS_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, false, "all", 'a', &(cmdargs).showall, \ "Show all containers (default shows just running)", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "no-stream", 0, &(cmdargs).nostream, \ - "Disable streaming stats and only pull the first result", NULL } + "Disable streaming stats and only pull the first result", NULL } extern const char g_cmd_stats_desc[]; extern const char g_cmd_stats_usage[]; extern struct client_arguments g_cmd_stats_args; int cmd_stats_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_STATS_H */ diff --git a/src/cmd/isula/extend/update.h b/src/cmd/isula/extend/update.h index 9628f04..b026800 100644 --- a/src/cmd/isula/extend/update.h +++ b/src/cmd/isula/extend/update.h @@ -17,27 +17,31 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define UPDATE_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_CALLBACK, false, "cpu-shares", 0, &(cmdargs).cr.cpu_shares, \ "CPU shares (relative weight)", command_convert_llong }, \ { CMD_OPT_TYPE_CALLBACK, false, "cpu-period", 0, &(cmdargs).cr.cpu_period, \ - "Limit CPU CFS (Completely Fair Scheduler) period", command_convert_llong }, \ + "Limit CPU CFS (Completely Fair Scheduler) period", command_convert_llong }, \ { CMD_OPT_TYPE_CALLBACK, false, "cpu-quota", 0, &(cmdargs).cr.cpu_quota, \ - "Limit CPU CFS (Completely Fair Scheduler) quota", command_convert_llong }, \ + "Limit CPU CFS (Completely Fair Scheduler) quota", command_convert_llong }, \ { CMD_OPT_TYPE_STRING, false, "cpuset-cpus", 0, &(cmdargs).cr.cpuset_cpus, \ - "CPUs in which to allow execution (0-3, 0,1)", NULL }, \ + "CPUs in which to allow execution (0-3, 0,1)", NULL }, \ { CMD_OPT_TYPE_STRING, false, "cpuset-mems", 0, &(cmdargs).cr.cpuset_mems, \ - "MEMs in which to allow execution (0-3, 0,1)", NULL }, \ + "MEMs in which to allow execution (0-3, 0,1)", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "kernel-memory", 0, &(cmdargs).cr.kernel_memory_limit, \ - "Kernel memory limit", command_convert_membytes }, \ + "Kernel memory limit", command_convert_membytes }, \ { CMD_OPT_TYPE_CALLBACK, false, "memory", 'm', &(cmdargs).cr.memory_limit, \ - "Memory limit", command_convert_membytes }, \ + "Memory limit", command_convert_membytes }, \ { CMD_OPT_TYPE_CALLBACK, false, "memory-reservation", 0, &(cmdargs).cr.memory_reservation, \ - "Memory soft limit", command_convert_membytes }, \ + "Memory soft limit", command_convert_membytes }, \ { CMD_OPT_TYPE_CALLBACK, false, "memory-swap", 0, &(cmdargs).cr.memory_swap, \ - "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", command_convert_memswapbytes }, \ + "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", command_convert_memswapbytes }, \ { CMD_OPT_TYPE_STRING, false, "restart", 0, &(cmdargs).restart, \ - "Restart policy to apply when a container exits", NULL } + "Restart policy to apply when a container exits", NULL } extern const char g_cmd_update_desc[]; extern const char g_cmd_update_usage[]; @@ -45,5 +49,9 @@ extern struct client_arguments g_cmd_update_args; int cmd_update_main(int argc, const char **argv); int update_checker(const struct client_arguments *args); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_UPDATE_H */ diff --git a/src/cmd/isula/images/images.h b/src/cmd/isula/images/images.h index 5fd55dd..9e46bbe 100644 --- a/src/cmd/isula/images/images.h +++ b/src/cmd/isula/images/images.h @@ -17,10 +17,18 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_images_desc[]; extern const char g_cmd_images_usage[]; extern struct client_arguments g_cmd_images_args; int cmd_images_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_IMAGES_LIST_H */ diff --git a/src/cmd/isula/images/load.h b/src/cmd/isula/images/load.h index e6f5555..372716b 100644 --- a/src/cmd/isula/images/load.h +++ b/src/cmd/isula/images/load.h @@ -17,10 +17,14 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define LOAD_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_STRING, false, "input", 'i', &(cmdargs).file, "Read from a manifest or an archive", NULL }, \ { CMD_OPT_TYPE_STRING, false, "tag", 0, &(cmdargs).tag, \ - "Name and optionally a tag in the 'name:tag' format, valid if type is docker", NULL } + "Name and optionally a tag in the 'name:tag' format, valid if type is docker", NULL } #define EMBEDDED_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_STRING, false, "type", 't', &(cmdargs).type, "Image type, embedded or docker(default)", NULL } @@ -29,5 +33,9 @@ extern const char g_cmd_load_desc[]; extern struct client_arguments g_cmd_load_args; int cmd_load_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_LOAD_H */ diff --git a/src/cmd/isula/images/login.h b/src/cmd/isula/images/login.h index e50c28e..d250334 100644 --- a/src/cmd/isula/images/login.h +++ b/src/cmd/isula/images/login.h @@ -16,11 +16,15 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define LOGIN_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_STRING, false, "username", 'u', &(cmdargs).username, "Username", NULL }, \ { CMD_OPT_TYPE_STRING, false, "password", 'p', &(cmdargs).password, "Password", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "password-stdin", 0, &(cmdargs).password_stdin, \ - "Take the password from stdin", NULL }, \ + "Take the password from stdin", NULL }, \ extern const char g_cmd_login_desc[]; @@ -28,5 +32,9 @@ extern const char g_cmd_login_usage[]; extern struct client_arguments g_cmd_login_args; int cmd_login_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_LOGIN_H */ diff --git a/src/cmd/isula/images/logout.h b/src/cmd/isula/images/logout.h index 7100f83..d3ee77b 100644 --- a/src/cmd/isula/images/logout.h +++ b/src/cmd/isula/images/logout.h @@ -16,10 +16,18 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_logout_desc[]; extern const char g_cmd_logout_usage[]; extern struct client_arguments g_cmd_logout_args; int cmd_logout_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_LOGOUT_H */ diff --git a/src/cmd/isula/images/pull.h b/src/cmd/isula/images/pull.h index 728ec4e..3cab4e4 100644 --- a/src/cmd/isula/images/pull.h +++ b/src/cmd/isula/images/pull.h @@ -18,6 +18,10 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_pull_desc[]; extern const char g_cmd_pull_usage[]; extern struct client_arguments g_cmd_pull_args; @@ -25,5 +29,9 @@ int client_pull(const struct client_arguments *args); int cmd_pull_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_PULL_IMAGE_H */ diff --git a/src/cmd/isula/images/rmi.h b/src/cmd/isula/images/rmi.h index bc8ec80..d2962e7 100644 --- a/src/cmd/isula/images/rmi.h +++ b/src/cmd/isula/images/rmi.h @@ -17,6 +17,10 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define RMI_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, false, "force", 'f', &(cmdargs).force, "Force removal of the image", NULL } @@ -25,5 +29,9 @@ extern const char g_cmd_rmi_usage[]; extern struct client_arguments g_cmd_rmi_args; int cmd_rmi_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_REMOVE_IMAGE_H */ diff --git a/src/cmd/isula/information/health.h b/src/cmd/isula/information/health.h index e9d4908..bc6919a 100644 --- a/src/cmd/isula/information/health.h +++ b/src/cmd/isula/information/health.h @@ -17,6 +17,10 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define HEALTH_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_STRING, false, "service", 'S', &(cmdargs).service, "GRPC service name", NULL } @@ -25,5 +29,9 @@ extern const char g_cmd_health_check_usage[]; extern struct client_arguments g_cmd_health_check_args; int cmd_health_check_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/cmd/isula/information/info.h b/src/cmd/isula/information/info.h index f358f9d..19eb055 100644 --- a/src/cmd/isula/information/info.h +++ b/src/cmd/isula/information/info.h @@ -17,10 +17,18 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_info_desc[]; extern const char g_cmd_info_usage[]; extern struct client_arguments g_cmd_info_args; int cmd_info_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_INFO_H */ diff --git a/src/cmd/isula/information/inspect.h b/src/cmd/isula/information/inspect.h index c83d3ec..dfe4252 100644 --- a/src/cmd/isula/information/inspect.h +++ b/src/cmd/isula/information/inspect.h @@ -17,16 +17,24 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define INSPECT_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_STRING, false, "format", 'f', &(cmdargs).format, \ "Format the output using the given go template", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "time", 't', &(cmdargs).time, \ - "Seconds to wait for inspect timeout (default 120)", command_convert_int } + "Seconds to wait for inspect timeout (default 120)", command_convert_int } extern const char g_cmd_inspect_desc[]; extern const char g_cmd_inspect_usage[]; extern struct client_arguments g_cmd_inspect_args; int cmd_inspect_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_INSPECT_H */ diff --git a/src/cmd/isula/information/logs.h b/src/cmd/isula/information/logs.h index c92314b..dfcfb11 100644 --- a/src/cmd/isula/information/logs.h +++ b/src/cmd/isula/information/logs.h @@ -17,10 +17,14 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define LOGS_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, false, "follow", 'f', &(cmdargs).follow, "Follow log output", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "tail", 0, &(cmdargs).tail, \ - "Number of lines to show from the end of the logs", callback_tail } + "Number of lines to show from the end of the logs", callback_tail } extern const char g_cmd_logs_desc[]; extern const char g_cmd_logs_usage[]; @@ -28,5 +32,10 @@ extern struct client_arguments g_cmd_logs_args; int callback_tail(command_option_t *option, const char *arg); int cmd_logs_main(int argc, const char **argv); + +#ifdef __cplusplus +} +#endif + #endif /* __CMD_LOGS_H */ diff --git a/src/cmd/isula/information/ps.h b/src/cmd/isula/information/ps.h index 65b77d0..1e76c6b 100644 --- a/src/cmd/isula/information/ps.h +++ b/src/cmd/isula/information/ps.h @@ -17,21 +17,29 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + #define LIST_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, false, "all", 'a', &(cmdargs).list_all, \ "Display all containers (default shows just running)", NULL }, \ { CMD_OPT_TYPE_BOOL, false, "quiet", 'q', &(cmdargs).dispname, "Only display numeric IDs", NULL }, \ { CMD_OPT_TYPE_CALLBACK, false, "filter", 'f', &(cmdargs).filters, \ - "Filter output based on conditions provided", command_append_array }, \ + "Filter output based on conditions provided", command_append_array }, \ { CMD_OPT_TYPE_BOOL, false, "no-trunc", 0, &(cmdargs).no_trunc, \ - "Don't truncate output", NULL }, \ + "Don't truncate output", NULL }, \ { CMD_OPT_TYPE_STRING, false, "format", 0, &(cmdargs).format, \ - "Format the output using the given go template", NULL } + "Format the output using the given go template", NULL } extern const char g_cmd_list_desc[]; extern const char g_cmd_list_usage[]; extern struct client_arguments g_cmd_list_args; int cmd_list_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_LIST_H */ diff --git a/src/cmd/isula/information/top.h b/src/cmd/isula/information/top.h index f96d780..6078195 100644 --- a/src/cmd/isula/information/top.h +++ b/src/cmd/isula/information/top.h @@ -17,10 +17,18 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_top_desc[]; extern const char g_cmd_top_usage[]; extern struct client_arguments g_cmd_top_args; int cmd_top_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_TOP_H */ diff --git a/src/cmd/isula/information/version.h b/src/cmd/isula/information/version.h index e8bab52..be23446 100644 --- a/src/cmd/isula/information/version.h +++ b/src/cmd/isula/information/version.h @@ -17,10 +17,18 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_version_desc[]; extern const char g_cmd_version_usage[]; extern struct client_arguments g_cmd_version_args; int cmd_version_main(int argc, const char **argv); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_VERSION_H */ diff --git a/src/cmd/isula/information/wait.h b/src/cmd/isula/information/wait.h index b9f89c2..594d538 100644 --- a/src/cmd/isula/information/wait.h +++ b/src/cmd/isula/information/wait.h @@ -17,11 +17,19 @@ #include "arguments.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const char g_cmd_wait_desc[]; extern const char g_cmd_wait_usage[]; extern struct client_arguments g_cmd_wait_args; int cmd_wait_main(int argc, const char **argv); int client_wait(const struct client_arguments *args, unsigned int *exit_code); +#ifdef __cplusplus +} +#endif + #endif /* __CMD_WAIT_H */ diff --git a/src/cmd/isula/main.c b/src/cmd/isula/main.c index 3da0621..c8d9ef0 100644 --- a/src/cmd/isula/main.c +++ b/src/cmd/isula/main.c @@ -33,6 +33,7 @@ #include "pause.h" #include "resume.h" #include "logs.h" +#include "events.h" #include "kill.h" #include "load.h" #include "update.h" @@ -137,6 +138,10 @@ struct command g_commands[] = { // `logs` sub-command "logs", cmd_logs_main, g_cmd_logs_desc, NULL, &g_cmd_logs_args }, + { + // `events` sub-command + "events", cmd_events_main, g_cmd_events_desc, NULL, &g_cmd_events_args + }, #endif { // `kill` sub-command diff --git a/src/cmd/isulad-shim/CMakeLists.txt b/src/cmd/isulad-shim/CMakeLists.txt new file mode 100644 index 0000000..846994e --- /dev/null +++ b/src/cmd/isulad-shim/CMakeLists.txt @@ -0,0 +1,12 @@ +# get current directory sources files +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} isulad_shim_srcs) + +set(CMD_ISULAD_SHIM_SRCS + ${isulad_shim_srcs} + PARENT_SCOPE + ) + +set(CMD_ISULAD_SHIM_INCS + ${CMAKE_CURRENT_SOURCE_DIR} + PARENT_SCOPE + ) diff --git a/src/cmd/isulad-shim/common.c b/src/cmd/isulad-shim/common.c new file mode 100644 index 0000000..2a1b9c5 --- /dev/null +++ b/src/cmd/isulad-shim/common.c @@ -0,0 +1,301 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: leizhongkai + * Create: 2020-1-21 + * Description: common functions of isulad-shim + ******************************************************************************/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +extern int g_log_fd; + +int set_fd_no_inherited(int fd) +{ + int ret = SHIM_ERR; + int flag = -1; + + flag = fcntl(fd, F_GETFD, 0); + if (flag < 0) { + return SHIM_ERR; + } + + ret = fcntl(fd, F_SETFD, flag | FD_CLOEXEC); + if (ret != 0) { + return SHIM_ERR; + } + + return SHIM_OK; +} + +ssize_t read_nointr(int fd, void *buf, size_t count) +{ + ssize_t nret; + + if (buf == NULL) { + return -1; + } + + for (;;) { + nret = read(fd, buf, count); + if (nret < 0 && (errno == EINTR || errno == EAGAIN)) { + continue; + } else { + break; + } + } + + return nret; +} + +ssize_t write_nointr(int fd, const void *buf, size_t count) +{ + ssize_t nret; + + if (buf == NULL) { + return -1; + } + + for (;;) { + nret = write(fd, buf, count); + if (nret < 0 && (errno == EINTR || errno == EAGAIN)) { + continue; + } else { + break; + } + } + return nret; +} + +bool file_exists(const char *f) +{ + struct stat buf; + int nret; + + if (f == NULL) { + return false; + } + + nret = stat(f, &buf); + if (nret < 0) { + return false; + } + return true; +} + +int cmd_combined_output(const char *binary, const char *params[], void *output, int *output_len) +{ + int ret = SHIM_ERR; + int exec_fd[2] = { -1, -1 }; + int stdio[2] = { -1, -1 }; + pid_t pid = 0; + char exec_buff[BUFSIZ + 1] = { 0 }; + ssize_t nread; + + if (pipe2(exec_fd, O_CLOEXEC) != 0) { + return SHIM_ERR; + } + + if (pipe2(stdio, O_CLOEXEC) != 0) { + return SHIM_ERR; + } + + pid = fork(); + if (pid == (pid_t) - 1) { + return SHIM_ERR; + } + + // child + if (pid == (pid_t)0) { + close(exec_fd[0]); + close(stdio[0]); + dup2(stdio[1], 1); + dup2(stdio[1], 2); + execvp(binary, (char * const *)params); + (void)dprintf(exec_fd[1], "fork/exec error: %s", strerror(errno)); + } + + // parent + close(exec_fd[1]); + close(stdio[1]); + nread = read_nointr(exec_fd[0], exec_buff, sizeof(exec_buff)); + if (nread > 0) { + ret = SHIM_ERR; + goto out; + } + *output_len = read_nointr(stdio[0], output, 8191); + + close(stdio[0]); + close(exec_fd[0]); + int status = 0; + wait(&status); + ret = SHIM_OK; +out: + if (ret != SHIM_OK && pid != 0) { + kill(pid, 9); + } + + return ret; +} + +int generate_random_str(char *id, size_t len) +{ + int fd = -1; + int num = 0; + size_t i; + const int m = 256; + + len = len / 2; + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) { + return SHIM_ERR; + } + for (i = 0; i < len; i++) { + int nret; + if (read(fd, &num, sizeof(int)) < 0) { + close(fd); + return SHIM_ERR; + } + unsigned char rs = (unsigned char)(num % m); + nret = snprintf((id + i * 2), ((len - i) * 2 + 1), "%02x", (unsigned int)rs); + if (nret < 0) { + close(fd); + return SHIM_ERR; + } + } + close(fd); + id[i * 2] = '\0'; + + return SHIM_OK; +} + +void write_message(int fd, const char *level, const char *fmt, ...) +{ +#define MAX_MSG_JSON_TEMPLATE 32 +#define MAX_MESSAGE_CONTENT_LEN 128 +#define MAX_MESSAGE_LEN (MAX_MSG_JSON_TEMPLATE + MAX_MESSAGE_CONTENT_LEN) + if (fd < 0) { + return; + } + + char buf[MAX_MESSAGE_CONTENT_LEN] = { 0 }; + char msg[MAX_MESSAGE_LEN] = { 0 }; + int nwrite = -1; + + va_list arg_list; + va_start(arg_list, fmt); + vsnprintf(buf, MAX_MESSAGE_CONTENT_LEN, fmt, arg_list); + va_end(arg_list); + + snprintf(msg, MAX_MESSAGE_LEN - 1, "{\"level\": \"%s\", \"msg\": \"%s\"}\n", level, buf); + nwrite = write(fd, msg, strlen(msg)); + if (nwrite != strlen(msg)) { + return; + } + + return; +} + +/* note: This function can only read small text file. */ +char *read_text_file(const char *path) +{ + char *buf = NULL; + long len = 0; + size_t readlen = 0; + FILE *filp = NULL; + const long max_size = 10 * 1024 * 1024; /* 10M */ + + if (path == NULL) { + return NULL; + } + + filp = fopen(path, "r"); + if (filp == NULL) { + goto err_out; + } + if (fseek(filp, 0, SEEK_END)) { + goto err_out; + } + + len = ftell(filp); + if (len > max_size) { + goto err_out; + } + if (fseek(filp, 0, SEEK_SET)) { + goto err_out; + } + + buf = (char *)calloc(1, (size_t)(len + 1)); + if (buf == NULL) { + goto err_out; + } + + readlen = fread(buf, 1, (size_t)len, filp); + if (((readlen < (size_t)len) && (!feof(filp))) || (readlen > (size_t)len)) { + if (buf != NULL) { + free(buf); + buf = NULL; + } + goto err_out; + } + + buf[(size_t)len] = 0; + +err_out: + + if (filp != NULL) { + fclose(filp); + } + + return buf; +} + +void close_fd(int *pfd) +{ + if (pfd != NULL && *pfd != -1) { + close(*pfd); + *pfd = -1; + } +} + +int open_no_inherit(const char *path, int flag, mode_t mode) +{ + int fd = -1; + int ret = SHIM_ERR; + + fd = open(path, flag, mode); + if (fd < 0) { + return -1; + } + + ret = set_fd_no_inherited(fd); + if (ret != SHIM_OK) { + close(fd); + return -1; + } + + return fd; +} + diff --git a/src/cmd/isulad-shim/common.h b/src/cmd/isulad-shim/common.h new file mode 100644 index 0000000..2a6c914 --- /dev/null +++ b/src/cmd/isulad-shim/common.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: leizhongkai + * Create: 2020-1-20 + * Description: common definition of isulad-shim + ******************************************************************************/ + +#ifndef __COMMON_H_ +#define __COMMON_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// error code +#define SHIM_ERR_BASE (-10000) +#define SHIM_SYS_ERR(err) (SHIM_ERR_BASE-err) +#define SHIM_OK 0 +#define SHIM_ERR -1 +#define SHIM_ERR_WAIT -2 +#define SHIM_ERR_NOT_REQUIRED -3 + +#define INFO_MSG "info" +#define WARN_MSG "warn" +#define ERR_MSG "error" + +#define DEFAULT_TIMEOUT 120 // sec +#define CONTAINER_ID_LEN 64 +#define MAX_RT_NAME_LEN 64 +#define MAX_CONSOLE_SOCK_LEN 32 + +#define MAX_RUNTIME_ARGS 20 + +#define SHIM_BINARY "isulad-shim" +#define SHIM_LOG_NAME "shim-log.json" + +#define CONTAINER_ACTION_REBOOT 129 +#define CONTAINER_ACTION_SHUTDOWN 130 + +ssize_t read_nointr(int fd, void *buf, size_t count); +ssize_t write_nointr(int fd, const void *buf, size_t count); + +char *read_text_file(const char *path); + +bool file_exists(const char *f); + +int cmd_combined_output(const char *binary, const char *params[], void *output, int *output_len); + +void write_message(int fd, const char *level, const char *fmt, ...); + +int generate_random_str(char *id, size_t len); + +void close_fd(int *pfd); + +int open_no_inherit(const char *path, int flag, mode_t mode); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/cmd/isulad-shim/main.c b/src/cmd/isulad-shim/main.c new file mode 100644 index 0000000..7b0b052 --- /dev/null +++ b/src/cmd/isulad-shim/main.c @@ -0,0 +1,162 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: leizhongkai + * Create: 2020-1-20 + * Description: main process of isulad-shim + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "process.h" + +int g_log_fd = -1; + +void signal_routine(int sig) +{ + switch (sig) { + case SIGALRM: + write_message(g_log_fd, ERR_MSG, "runtime timeout"); + exit(1); + default: + break; + } +} + +static void set_timeout_exit(unsigned int timeout) +{ + signal(SIGALRM, signal_routine); + (void)alarm(timeout); +} + +static void released_timeout_exit() +{ + (void)alarm(0); + signal(SIGALRM, SIG_IGN); +} + +static int set_subreaper() +{ + int ret = SHIM_ERR; + ret = prctl(PR_SET_CHILD_SUBREAPER, 1); + if (ret != SHIM_OK) { + return SHIM_SYS_ERR(errno); + } + + return SHIM_OK; +} + +static int parse_args(int argc, char **argv, char **cid, char **bundle, char **rt_name, char **log_level) +{ + if (argc < 4) { + return SHIM_ERR; + } + + *cid = strdup(argv[1]); + *bundle = strdup(argv[2]); + *rt_name = strdup(argv[3]); + if (*cid == NULL || *bundle == NULL || rt_name == NULL) { + return SHIM_ERR; + } + + if (argc > 4) { + *log_level = strdup(argv[4]); + if (*log_level == NULL) { + return SHIM_ERR; + } + } + + return SHIM_OK; +} + + +int main(int argc, char **argv) +{ + char *container_id = NULL; + char *bundle = NULL; + char *rt_name = NULL; + char *log_level = NULL; + int ret = SHIM_ERR; + int efd = -1; + process_t *p = NULL; + + g_log_fd = open_no_inherit(SHIM_LOG_NAME, O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0640); + if (g_log_fd < 0) { + _exit(EXIT_FAILURE); + } + + set_timeout_exit(DEFAULT_TIMEOUT); + + ret = set_subreaper(); + if (ret != SHIM_OK) { + write_message(g_log_fd, ERR_MSG, "set subreaper failed:%d", ret); + exit(EXIT_FAILURE); + } + + ret = parse_args(argc, argv, &container_id, &bundle, &rt_name, &log_level); + if (ret != SHIM_OK) { + write_message(g_log_fd, ERR_MSG, "parse args failed:%d", ret); + exit(EXIT_FAILURE); + } + + p = new_process(container_id, bundle, rt_name); + if (p == NULL) { + write_message(g_log_fd, ERR_MSG, "new process failed"); + exit(EXIT_FAILURE); + } + + // open exit pipe + if (!p->state->exec) { + if (p->state->exit_fifo != NULL) { + efd = open_no_inherit("exit_fifo", O_WRONLY, -1); + if (efd < 0) { + write_message(g_log_fd, ERR_MSG, "open exit pipe failed:%d", SHIM_SYS_ERR(errno)); + exit(EXIT_FAILURE); + } + p->exit_fd = efd; + } + } + + // create main loop and start epoll + ret = process_io_init(p); + if (ret != SHIM_OK) { + write_message(g_log_fd, ERR_MSG, "process io init failed:%d", ret); + exit(EXIT_FAILURE); + } + + ret = open_io(p); + if (ret != SHIM_OK) { + exit(EXIT_FAILURE); + } + + ret = create_process(p); + if (ret != SHIM_OK) { + exit(EXIT_FAILURE); + } + + released_timeout_exit(); + + ret = process_signal_handle_routine(p); + if (ret != SHIM_OK) { + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} diff --git a/src/cmd/isulad-shim/process.c b/src/cmd/isulad-shim/process.c new file mode 100644 index 0000000..5f929b7 --- /dev/null +++ b/src/cmd/isulad-shim/process.c @@ -0,0 +1,1018 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: leizhongkai + * Create: 2020-1-20 + * Description: process operation encapsulation + ******************************************************************************/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "process.h" + +#define MAX_EVENTS 100 +#define DEFAULT_IO_COPY_BUF (16*1024) + +extern int g_log_fd; + +typedef int (*epoll_loop_callback_t)(int fd, uint32_t event, void *data); + +struct epoll_loop_handler { + epoll_loop_callback_t cb; + int epfd; + int cbfd; + void *cbdata; +}; + + +static shim_client_process_state* load_process() +{ + parser_error err = NULL; + shim_client_process_state *p_state = NULL; + p_state = shim_client_process_state_parse_file("process.json", NULL, &err); + if (p_state == NULL) { + write_message(g_log_fd, ERR_MSG, "parse process state failed"); + goto out; + } +out: + if (err != NULL) { + free(err); + } + + return p_state; +} + +static int open_fifo_noblock(const char *path, mode_t mode) +{ + int fd = -1; + + // By default, We consider that the file has been created by isulad + fd = open_no_inherit(path, mode | O_NONBLOCK, -1); + if (fd < 0) { + write_message(g_log_fd, ERR_MSG, "open fifo file failed:%d", SHIM_SYS_ERR(errno)); + return -1; + } + + return fd; +} + +static int receive_fd(int sock) +{ + u_char *pfd = NULL; + int fd = -1; + int cmsgsize = CMSG_LEN(sizeof(int)); + struct cmsghdr* cmptr = (struct cmsghdr*)calloc(1, cmsgsize); + if (cmptr == NULL) { + return -1; + } + + char buf[32] = { 0 }; + struct iovec iov[1]; + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + + struct msghdr msg; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = cmptr; + msg.msg_controllen = cmsgsize; + + int ret = recvmsg(sock, &msg, 0); + if (ret == -1) { + free(cmptr); + write_message(g_log_fd, ERR_MSG, "get console fd failed:%d", SHIM_SYS_ERR(errno)); + return -1; + } + + pfd = CMSG_DATA(cmptr); + fd = *(int *)pfd; + free(cmptr); + + return fd; +} + +static bool check_fd(int fd) +{ + struct termios term; + int ret = ioctl(fd, TCGETS, &term); + if (ret != 0) { + return false; + } + + return true; +} + +static int add_io_dispatch(int epfd, io_thread_t *io_thd, int from, int to) +{ + int ret = SHIM_ERR; + + if (io_thd == NULL || io_thd->ioc == NULL) { + return SHIM_ERR; + } + + io_copy_t *ioc = io_thd->ioc; + fd_node_t *fn = (fd_node_t *)calloc(1, sizeof(fd_node_t)); + if (fn == NULL) { + return SHIM_ERR; + } + fn->fd = to; + fn->next = NULL; + + pthread_mutex_lock(&(ioc->mutex)); + // add src fd + if (from != -1 && ioc->fd_from == -1) { + ioc->fd_from = from; + struct epoll_event ev; + ev.events = EPOLLIN; + ev.data.ptr = io_thd; + + ret = epoll_ctl(epfd, EPOLL_CTL_ADD, from, &ev); + if (ret != SHIM_OK) { + write_message(g_log_fd, ERR_MSG, "add fd %d to epoll loop failed:%d", from, SHIM_SYS_ERR(errno)); + pthread_mutex_unlock(&(ioc->mutex)); + return SHIM_ERR; + } + } + + // add dest fd + if (to != -1) { + if (ioc->fd_to == NULL) { + ioc->fd_to = fn; + } else { + fd_node_t *tmp = ioc->fd_to; + while (tmp->next != NULL) { + tmp = tmp->next; + } + tmp->next = fn; + } + } + pthread_mutex_unlock(&(ioc->mutex)); + + return SHIM_OK; +} + +static void remove_io_dispatch(io_thread_t *io_thd, int from, int to) +{ + if (io_thd == NULL || io_thd->ioc == NULL) { + return; + } + io_copy_t *ioc = io_thd->ioc; + + pthread_mutex_lock(&(ioc->mutex)); + fd_node_t *tmp = NULL; + do { + // remove src fd + if (from != -1 && from == ioc->fd_from) { + struct epoll_event ev; + ev.events = EPOLLIN; + ev.data.fd = ioc->fd_from; + (void)epoll_ctl(io_thd->epfd, EPOLL_CTL_DEL, ioc->fd_from, &ev); + } + + // remove dest fd + if (ioc->fd_to == NULL) { + break; + } + if (ioc->fd_to->fd == to) { + tmp = ioc->fd_to; + ioc->fd_to = ioc->fd_to->next; + break; + } + fd_node_t *pre = NULL; + tmp = ioc->fd_to->next; + while (tmp != NULL && tmp->fd != to) { + pre = tmp; + tmp = tmp->next; + } + if (tmp != NULL) { + pre->next = tmp->next; + } + } while (0); + if (tmp != NULL) { + free(tmp); + } + pthread_mutex_unlock(&(ioc->mutex)); +} + +static void* task_io_copy(void *data) +{ + io_thread_t *io_thd = (io_thread_t*)data; + if (io_thd == NULL || io_thd->ioc == NULL) { + return NULL; + } + io_copy_t *ioc = io_thd->ioc; + char *buf = calloc(1, DEFAULT_IO_COPY_BUF + 1); + if (buf == NULL) { + _exit(EXIT_FAILURE); + } + + for (;;) { + memset(buf, 0, DEFAULT_IO_COPY_BUF); + sem_wait(&(io_thd->sem_thd)); + if (io_thd->shutdown) { + break; + } + + int r_count = read(ioc->fd_from, buf, DEFAULT_IO_COPY_BUF); + if (r_count == -1) { + // If errno == EAGAIN, that means we have read all data + if (errno == EAGAIN || errno == EINTR) { + continue; + } + break; + } else if (r_count == 0) { + // End of file. The remote has closed the connection. + break; + } else { + fd_node_t *fn = ioc->fd_to; + for (; fn != NULL; fn = fn->next) { + int w_count; + w_count = write_nointr(fn->fd, buf, r_count); + if (w_count < 0) { + // remove the write fd + remove_io_dispatch(io_thd, -1, fn->fd); + } + } + } + } + struct epoll_event ev; + ev.events = EPOLLIN; + ev.data.fd = ioc->fd_from; + (void)epoll_ctl(io_thd->epfd, EPOLL_CTL_DEL, ioc->fd_from, &ev); + + free(buf); + + return NULL; +} + +static void do_io_copy(int fd, uint32_t event, void *data) +{ + io_thread_t *thd = (io_thread_t*)data; + if (thd->ioc == NULL || fd != thd->ioc->fd_from) { + return; + } + + if (event & EPOLLIN) { + sem_post(&thd->sem_thd); + } else if (event & EPOLLHUP) { + thd->shutdown = true; + sem_post(&thd->sem_thd); + } + + return; +} + +static int process_io_start(process_t *p, int std_id) +{ + int ret = SHIM_ERR; + io_thread_t *io_thd = NULL; + io_copy_t *ioc = NULL; + + ioc = (io_copy_t *)calloc(1, sizeof(io_copy_t)); + if (ioc == NULL) { + goto failure; + } + ioc->id = std_id; + ioc->fd_from = -1; + ioc->fd_to = NULL; + if (pthread_mutex_init(&(ioc->mutex), NULL) != 0) { + goto failure; + } + + io_thd = (io_thread_t *)calloc(1, sizeof(io_thread_t)); + if (io_thd == NULL) { + goto failure; + } + if (sem_init(&io_thd->sem_thd, 0, 0) == -1) { + write_message(g_log_fd, ERR_MSG, "sem init failed:%d", SHIM_SYS_ERR(errno)); + goto failure; + } + io_thd->epfd = p->io_loop_fd; + io_thd->ioc = ioc; + io_thd->shutdown = false; + p->io_threads[std_id] = io_thd; + + ret = pthread_create(&(io_thd->tid), NULL, task_io_copy, io_thd); + if (ret != SHIM_OK) { + write_message(g_log_fd, ERR_MSG, "thread io copy create failed:%d", SHIM_SYS_ERR(errno)); + goto failure; + } + + ret = SHIM_OK; + + return ret; + +failure: + if (ioc != NULL) { + pthread_mutex_destroy(&(ioc->mutex)); + free(ioc); + } + if (io_thd != NULL) { + free(io_thd); + } + + return SHIM_ERR; +} + +static int start_io_copy_threads(process_t *p) +{ + int ret = SHIM_ERR; + int i; + + for (i = 0; i < 3; i++) { + ret = process_io_start(p, i); + if (ret != SHIM_OK) { + return SHIM_ERR; + } + } + return SHIM_OK; +} + +static void destory_io_thread(process_t *p, int std_id) +{ + io_thread_t *io_thd = p->io_threads[std_id]; + if (io_thd == NULL) { + return; + } + + io_thd->shutdown = true; + sem_post(&io_thd->sem_thd); + pthread_join(io_thd->tid, NULL); + if (io_thd->ioc != NULL) { + free(io_thd->ioc); + } + free(io_thd); + p->io_threads[std_id] = NULL; +} + +static int connect_to_isulad(process_t *p, int std_id, const char *isulad_stdio, int fd) +{ + mode_t mode; + int fd_isulad = -1; + int *fd_from = NULL; + int *fd_to = NULL; + + if (std_id == stdid_in) { + mode = O_RDONLY; + fd_from = &fd_isulad; + fd_to = &fd; + } else { + mode = O_WRONLY; + fd_from = &fd; + fd_to = &fd_isulad; + } + + if (isulad_stdio != NULL && file_exists(isulad_stdio)) { + fd_isulad = open_fifo_noblock(isulad_stdio, mode); + if (fd_isulad < 0) { + return SHIM_ERR; + } + } + + if (*fd_from != -1) { + return add_io_dispatch(p->io_loop_fd, p->io_threads[std_id], *fd_from, *fd_to); + } + + // if no I/O source is available, the I/O thread nead to be destroyed + destory_io_thread(p, std_id); + + return SHIM_OK; +} + +static void* task_console_accept(void *data) +{ + int conn_fd = -1; + int recv_fd = -1; + int ret = SHIM_ERR; + console_accept_t *ac = (console_accept_t*)data; + + conn_fd = accept(ac->listen_fd, NULL, NULL); + if (conn_fd < 0) { + write_message(g_log_fd, ERR_MSG, "accept from fd %d failed:%d", ac->listen_fd, SHIM_SYS_ERR(errno)); + exit(EXIT_FAILURE); + } + + recv_fd = receive_fd(conn_fd); + if (check_fd(recv_fd) != true) { + write_message(g_log_fd, ERR_MSG, "check console fd failed"); + exit(EXIT_FAILURE); + } + + // do console io copy + // + // p.state.stdin---->runtime.console + ret = connect_to_isulad(ac->p, stdid_in, ac->p->state->isulad_stdin, recv_fd); + if (ret != SHIM_OK) { + exit(EXIT_FAILURE); + } + + // p.state.stdout<------runtime.console + ret = connect_to_isulad(ac->p, stdid_out, ac->p->state->isulad_stdout, recv_fd); + if (ret != SHIM_OK) { + exit(EXIT_FAILURE); + } + + // if the terminal is used, we do not need to active the io copy of stderr pipe + destory_io_thread(ac->p, stdid_err); + + // release listen socket + close_fd(&ac->listen_fd); + if (ac->p->console_sock_path != NULL) { + unlink(ac->p->console_sock_path); + free(ac->p->console_sock_path); + ac->p->console_sock_path = NULL; + } + free(ac); + + return NULL; +} + +static void* task_io_loop(void *data) +{ + process_t *p = (process_t*)data; + int wait_fds = 0; + struct epoll_event evs[MAX_EVENTS]; + int i; + + p->io_loop_fd = epoll_create1(EPOLL_CLOEXEC); + if (p->io_loop_fd < 0) { + write_message(g_log_fd, ERR_MSG, "epoll create failed:%d", SHIM_SYS_ERR(errno)); + exit(EXIT_FAILURE); + } + + // begin wait + while (1) { + wait_fds = epoll_wait(p->io_loop_fd, evs, MAX_EVENTS, -1); + if (wait_fds < 0) { + if (errno == EINTR) { + continue; + } + _exit(EXIT_FAILURE); + } + + for (i = 0; i < wait_fds; i++) { + io_thread_t *thd_io = (io_thread_t*)evs[i].data.ptr; + do_io_copy(thd_io->ioc->fd_from, evs[i].events, thd_io); + } + } +} + +static int new_temp_console_path(process_t *p) +{ +#define RAND_NUM_LEN 9 + int ret = SHIM_ERR; + char str_rand[RAND_NUM_LEN + 1] = { 0 }; + + ret = generate_random_str(str_rand, RAND_NUM_LEN); + if (ret != SHIM_OK) { + return SHIM_ERR; + } + p->console_sock_path = (char *)calloc(1, MAX_CONSOLE_SOCK_LEN + 1); + if (p->console_sock_path == NULL) { + return SHIM_ERR; + } + snprintf(p->console_sock_path, MAX_CONSOLE_SOCK_LEN, "/tmp/isulad%s-pty.sock", str_rand); + + return SHIM_OK; +} + +static int console_init(process_t *p) +{ + int ret = SHIM_ERR; + int fd = -1; + struct sockaddr_un addr; + console_accept_t* ac = NULL; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + return SHIM_SYS_ERR(errno); + } + + (void)memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + (void)strcpy(addr.sun_path, p->console_sock_path); + + // bind + ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); + if (ret < 0) { + write_message(g_log_fd, ERR_MSG, "bind console fd failed:%d", SHIM_SYS_ERR(errno)); + goto failure; + } + + // listen + ret = listen(fd, 2); + if (ret < 0) { + write_message(g_log_fd, ERR_MSG, "listen console fd failed:%d", SHIM_SYS_ERR(errno)); + goto failure; + } + + ac = (console_accept_t*)calloc(1, sizeof(console_accept_t)); + if (ac == NULL) { + goto failure; + } + ac->p = p; + ac->listen_fd = fd; + + pthread_t tid_accept; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + ret = pthread_create(&tid_accept, &attr, task_console_accept, ac); + if (ret != SHIM_OK) { + goto failure; + } + + return SHIM_OK; +failure: + close_fd(&fd); + if (ac != NULL) { + free(ac); + } + + return SHIM_ERR; +} + +static stdio_t* initialize_io(process_t *p) +{ + int ret = SHIM_ERR; + int stdio_fd[3][2] = { {-1, -1}, {-1, -1}, {-1, -1} }; + int i, j; + + stdio_t *stdio = (stdio_t *)calloc(1, sizeof(stdio_t)); + p->stdio = (stdio_t *)calloc(1, sizeof(stdio_t)); + if (p->stdio == NULL || stdio == NULL) { + goto failure; + } + + if ((pipe2(stdio_fd[0], O_CLOEXEC | O_NONBLOCK) != 0) || + (pipe2(stdio_fd[1], O_CLOEXEC | O_NONBLOCK) != 0) || + (pipe2(stdio_fd[2], O_CLOEXEC | O_NONBLOCK) != 0)) { + write_message(g_log_fd, ERR_MSG, "open pipe failed when init io:%d", SHIM_SYS_ERR(errno)); + goto failure; + } + + p->stdio->in = stdio_fd[0][0];// r + stdio->in = stdio_fd[0][1]; // w + p->stdio->out = stdio_fd[1][1];// w + stdio->out = stdio_fd[1][0];// r + p->stdio->err = stdio_fd[2][1];// w + stdio->err = stdio_fd[2][0];// r + + for (i = 0; i < 3; i++) { + for (j = 0; j < 2; j++) { + ret = fchown(stdio_fd[i][j], p->state->root_uid, p->state->root_gid); + if (ret != SHIM_OK) { + goto failure; + } + } + } + + return stdio; + +failure: + if (stdio != NULL) { + free(stdio); + stdio = NULL; + } + if (p->stdio != NULL) { + free(p->stdio); + p->stdio = NULL; + } + for (i = 0; i < 3; i++) { + for (j = 0; j < 2; j++) { + if (stdio_fd[i][j] > 0) { + close(stdio_fd[i][j]); + } + } + } + + return NULL; +} + +static int open_terminal_io(process_t *p) +{ + int ret = SHIM_ERR; + + ret = new_temp_console_path(p); + if (ret != SHIM_OK) { + write_message(g_log_fd, ERR_MSG, "get temp console sock path failed"); + return SHIM_ERR; + } + + // begin listen and accept fd from p->console_sock_path + ret = console_init(p); + if (ret != SHIM_OK) { + write_message(g_log_fd, ERR_MSG, "init console failed:%d", ret); + return SHIM_ERR; + } + return SHIM_OK; +} + + +static int open_generic_io(process_t *p) +{ + int ret = SHIM_ERR; + + stdio_t *io = initialize_io(p); + if (io == NULL) { + return SHIM_ERR; + } + p->shim_io = io; + // stdin + ret = connect_to_isulad(p, stdid_in, p->state->isulad_stdin, io->in); + if (ret != SHIM_OK) { + return SHIM_ERR; + } + // stdout + ret = connect_to_isulad(p, stdid_out, p->state->isulad_stdout, io->out); + if (ret != SHIM_OK) { + return SHIM_ERR; + } + // stderr + ret = connect_to_isulad(p, stdid_err, p->state->isulad_stderr, io->err); + if (ret != SHIM_OK) { + return SHIM_ERR; + } + + return SHIM_OK; +} + +static void adapt_for_isulad_stdin(process_t *p) +{ + // iSulad: close stdin pipe if we do not want open_stdin with container stdin just like lxc + if (!p->state->open_stdin && !file_exists(p->state->isulad_stdin)) { + if (p->shim_io != NULL && p->shim_io->in != -1) { + close(p->shim_io->in); + p->shim_io->in = -1; + } + } +} + +process_t* new_process(char *id, char *bundle, char *runtime) +{ + shim_client_process_state* p_state; + process_t* p = NULL; + int i; + + p_state = load_process(); + if (p_state == NULL) { + return NULL; + } + + p = (process_t*)calloc(1, sizeof(process_t)); + if (p == NULL) { + return NULL; + } + p->id = id; + p->bundle = bundle; + p->runtime = runtime; + p->state = p_state; + + p->console_sock_path = NULL; + p->exit_fd = -1; + p->io_loop_fd = -1; + p->ctr_pid = -1; + p->stdio = NULL; + p->shim_io = NULL; + for (i = 0; i < 3; i ++) { + p->io_threads[i] = NULL; + } + + return p; +} + +int open_io(process_t *p) +{ + int ret = SHIM_ERR; + + ret = start_io_copy_threads(p); + if (ret != SHIM_OK) { + return SHIM_ERR; + } + + if (p->state->terminal) { + return open_terminal_io(p); + } + + return open_generic_io(p); +} + + +int process_io_init(process_t *p) +{ + int ret = SHIM_ERR; + + pthread_t tid_loop; + ret = pthread_create(&tid_loop, NULL, task_io_loop, p); + if (ret != SHIM_OK) { + return SHIM_SYS_ERR(errno); + } + + return SHIM_OK; +} + +static void get_runtime_cmd(process_t *p, const char *log_path, const char *pid_path, const char *process_desc, + const char *params[]) +{ + int i = 0; + int j; + params[i++] = p->runtime; + for (j = 0; j < p->state->runtime_args_len; j++) { + params[i++] = p->state->runtime_args[j]; + } + params[i++] = "--log"; + + params[i++] = log_path; + params[i++] = "--log-format"; + params[i++] = "json"; + if (p->state->exec && process_desc != NULL) { + params[i++] = "exec"; + params[i++] = "-d"; + params[i++] = "--process"; + params[i++] = process_desc; + } else { + params[i++] = "create"; + params[i++] = "--bundle"; + params[i++] = p->bundle; + } + params[i++] = "--pid-file"; + params[i++] = pid_path; + if (p->console_sock_path != NULL) { + params[i++] = "--console-socket"; + params[i++] = p->console_sock_path; + } + params[i++] = p->id; +} + +static int reap_container(int ctr_pid, int *status) +{ +#define EXIT_SIGNAL_OFFSET 128 + int st; + struct rusage rus; + + // block wait + int pid = wait4(-1, &st, 0, &rus); + if (pid <= 0) { + return SHIM_ERR_WAIT; + } else if (pid != ctr_pid) { + return SHIM_ERR; + } + + if (WIFSIGNALED(st)) { + *status = EXIT_SIGNAL_OFFSET + WTERMSIG(st); + } else { + *status = WEXITSTATUS(st); + } + + return SHIM_OK; +} + +static void process_kill_all(process_t *p) +{ + if (p->state->exec) { + return; + } + + const char *params[MAX_RUNTIME_ARGS] = { NULL }; + char output[BUFSIZ] = { 0 }; + int output_len = BUFSIZ; + int i = 0; + int j; + + params[i++] = p->runtime; + for (j = 0; j < p->state->runtime_args_len; j++) { + params[i++] = p->state->runtime_args[j]; + } + params[i++] = "kill"; + params[i++] = "--all"; + params[i++] = p->id; + params[i++] = "SIGKILL"; + + (void)cmd_combined_output(p->runtime, params, output, &output_len); + + return; +} + +void process_delete(process_t *p) +{ + if (p->state->exec) { + return; + } + + const char *params[MAX_RUNTIME_ARGS] = { NULL }; + char output[BUFSIZ] = { 0 }; + int output_len = BUFSIZ; + int i = 0; + int j; + char log_path[PATH_MAX] = { 0 }; + char *cwd; + + cwd = getcwd(NULL, 0); + if (cwd == NULL) { + write_message(g_log_fd, ERR_MSG, "get cwd failed when do process delete"); + return; + } + snprintf(log_path, PATH_MAX, "%s/log.json", cwd); + + params[i++] = p->runtime; + for (j = 0; j < p->state->runtime_args_len; j++) { + params[i++] = p->state->runtime_args[j]; + } + params[i++] = "--log"; + params[i++] = log_path; + params[i++] = "--log-format"; + params[i++] = "json"; + + params[i++] = "delete"; + params[i++] = "--force"; + params[i++] = p->id; + + (void)cmd_combined_output(p->runtime, params, output, &output_len); + free(cwd); + + return; +} + +int create_process(process_t *p) +{ + int ret = -1; + char *data = NULL; + int exec_fd[2] = { -1, -1 }; + char exec_buff[BUFSIZ + 1] = { 0 }; + int nread = -1; + + if (pipe2(exec_fd, O_CLOEXEC) != 0) { + write_message(g_log_fd, ERR_MSG, "create pipe failed when create process:%d", SHIM_SYS_ERR(errno)); + return SHIM_ERR; + } + + pid_t pid = fork(); + if (pid == (pid_t) - 1) { + write_message(g_log_fd, ERR_MSG, "fork failed when create process:%d", SHIM_SYS_ERR(errno)); + return SHIM_ERR; + } + + // child:runtime + if (pid == (pid_t)0) { + close_fd(&exec_fd[0]); + if (p->shim_io != NULL) { + if (p->shim_io->in != -1) { + close(p->shim_io->in); + p->shim_io->in = -1; + dup2(p->stdio->in, 0); + } + if (p->shim_io->out != -1) { + close(p->shim_io->out); + p->shim_io->out = -1; + dup2(p->stdio->out, 1); + } + if (p->shim_io->err != -1) { + close(p->shim_io->err); + p->shim_io->err = -1; + dup2(p->stdio->err, 2); + } + } + + char *cwd = getcwd(NULL, 0); + char *log_path = (char *)calloc(1, PATH_MAX); + char *pid_path = (char *)calloc(1, PATH_MAX); + if (cwd == NULL || log_path == NULL || pid_path == NULL) { + (void)dprintf(exec_fd[1], "memory error: %s", strerror(errno)); + _exit(EXIT_FAILURE); + } + + snprintf(log_path, PATH_MAX, "%s/log.json", cwd); + snprintf(pid_path, PATH_MAX, "%s/pid", cwd); + + char *process_desc = NULL; + if (p->state->exec) { + process_desc = (char *)calloc(1, PATH_MAX); + if (process_desc == NULL) { + (void)dprintf(exec_fd[1], "memory error: %s", strerror(errno)); + _exit(EXIT_FAILURE); + } + snprintf(process_desc, PATH_MAX, "%s/process.json", cwd); + } + + const char *params[MAX_RUNTIME_ARGS] = { 0 }; + get_runtime_cmd(p, log_path, pid_path, process_desc, params); + execvp(p->runtime, (char * const *)params); + (void)dprintf(exec_fd[1], "fork/exec error: %s", strerror(errno)); + _exit(EXIT_FAILURE); + } + + // parent + close_fd(&exec_fd[1]); + if (p->stdio != NULL) { + close_fd(&p->stdio->in); + close_fd(&p->stdio->out); + close_fd(&p->stdio->err); + } + nread = read_nointr(exec_fd[0], exec_buff, sizeof(exec_buff)); + if (nread > 0) { + write_message(g_log_fd, ERR_MSG, "runtime error"); + ret = SHIM_ERR; + goto out; + } + + // block to wait pid exit + ret = waitpid(pid, NULL, 0); + if (ret != pid) { + write_message(g_log_fd, ERR_MSG, "wait runtime failed:%d", SHIM_SYS_ERR(errno)); + ret = SHIM_ERR; + goto out; + } + + // save pid + data = read_text_file("pid"); + if (data == NULL) { + write_message(g_log_fd, ERR_MSG, "read pid of runtime failed"); + goto out; + } + int ctr_pid = atoi(data); + if (ctr_pid <= 0) { + goto out; + } + + p->ctr_pid = ctr_pid; + adapt_for_isulad_stdin(p); + ret = SHIM_OK; + +out: + close_fd(&exec_fd[0]); + if (data != NULL) { + free(data); + } + + return ret; +} + +int process_signal_handle_routine(process_t *p) +{ + int ret = SHIM_ERR; + bool exit_shim = false; + int i; + + for (;;) { + int status; + ret = reap_container(p->ctr_pid, &status); + if (ret == SHIM_OK) { + exit_shim = true; + if (status == CONTAINER_ACTION_REBOOT) { + ret = setenv("CONTAINER_ACTION", "reboot", 1); + if (ret != SHIM_OK) { + write_message(g_log_fd, WARN_MSG, "set reboot action failed:%d", SHIM_SYS_ERR(errno)); + } + } else if (status == CONTAINER_ACTION_SHUTDOWN) { + ret = setenv("CONTAINER_ACTION", "shutdown", 1); + if (ret != SHIM_OK) { + write_message(g_log_fd, WARN_MSG, "set shutdown action failed:%d", SHIM_SYS_ERR(errno)); + } + } + } else if (ret == SHIM_ERR_WAIT) { + // avoid thread entering the infinite loop + usleep(1000); + continue; + } + if (exit_shim) { + process_kill_all(p); + process_delete(p); + if (p->exit_fd > 0) { + (void)write_nointr(p->exit_fd, &status, sizeof(int)); + } + for (i = 0; i < 3; i ++) { + destory_io_thread(p, i); + } + return status; + } + } +} + diff --git a/src/cmd/isulad-shim/process.h b/src/cmd/isulad-shim/process.h new file mode 100644 index 0000000..71eca2e --- /dev/null +++ b/src/cmd/isulad-shim/process.h @@ -0,0 +1,100 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: leizhongkai + * Create: 2020-1-20 + * Description: process definition + ******************************************************************************/ + +#ifndef __SHIM_PROCESS_H_ +#define __SHIM_PROCESS_H_ + +#include +#include +#include +#include "shim_client_process_state.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + stdid_in = 0, + stdid_out, + stdid_err +}; + +typedef struct { + int in; + int out; + int err; +} stdio_t; + +typedef struct fd_node { + int fd; + struct fd_node *next; +} fd_node_t; + +typedef struct { + int fd_from; + fd_node_t *fd_to; + int id;// 0,1,2 + pthread_mutex_t mutex; +} io_copy_t; + +typedef struct { + int epfd; + pthread_t tid; + pthread_attr_t attr; + sem_t sem_thd; + io_copy_t *ioc; + bool shutdown; +} io_thread_t; + +typedef struct process { + char *id; + char *bundle; + char *runtime; + char *console_sock_path; + int io_loop_fd; + int exit_fd; + int ctr_pid; + stdio_t *stdio; + stdio_t *shim_io; + io_thread_t *io_threads[3];// stdin,stdout,stderr + shim_client_process_state *state; +} process_t; + +typedef struct { + int listen_fd; + process_t *p; +} console_accept_t; + +typedef struct { + int pid; + int status; +} process_exit_t; + + + +process_t* new_process(char *id, char *bundle, char *runtime); + +int open_io(process_t *p); +int process_io_init(process_t *p); +int create_process(process_t *p); +int process_signal_handle_routine(process_t *p); +void process_delete(process_t *p); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/cmd/isulad/arguments.c b/src/cmd/isulad/arguments.c index 7381a87..4c1ecde 100644 --- a/src/cmd/isulad/arguments.c +++ b/src/cmd/isulad/arguments.c @@ -157,6 +157,7 @@ int service_arguments_init(struct service_arguments *args) args->default_ulimit = NULL; args->default_ulimit_len = 0; args->json_confs->websocket_server_listening_port = DEFAULT_WEBSOCKET_SERVER_LISTENING_PORT; + args->json_confs->selinux_enabled = false; ret = 0; diff --git a/src/cmd/isulad/commands.h b/src/cmd/isulad/commands.h index d09037e..f3228bf 100644 --- a/src/cmd/isulad/commands.h +++ b/src/cmd/isulad/commands.h @@ -102,7 +102,9 @@ int update_default_ulimit(struct service_arguments *args); "Default ulimits for containers (default [])", command_default_ulimit_append }, \ { CMD_OPT_TYPE_CALLBACK, false, "websocket-server-listening-port", 0, \ &(cmdargs)->json_confs->websocket_server_listening_port, \ - "CRI websocket streaming service listening port (default 10350)", command_convert_uint } + "CRI websocket streaming service listening port (default 10350)", command_convert_uint }, \ + { CMD_OPT_TYPE_BOOL, false, "selinux-enabled", 0, &(cmdargs)->json_confs->selinux_enabled, \ + "Enable selinux support", NULL} #endif /* __COMMAND_H */ diff --git a/src/cmd/isulad/main.c b/src/cmd/isulad/main.c index 2ecd6b0..bb8a252 100644 --- a/src/cmd/isulad/main.c +++ b/src/cmd/isulad/main.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -56,6 +57,7 @@ #include "supervisor.h" #include "containers_gc.h" #include "plugin.h" +#include "selinux_label.h" #ifdef ENABLE_OCI_IMAGE @@ -772,6 +774,80 @@ out: return ret; } +static int overlay_supports_selinux(bool *supported) +{ +#define KALLSYMS_ITEM_MAX_LEN 100 + int ret = 0; + FILE *fp = NULL; + char *buf = NULL; + size_t len; + ssize_t num; + + *supported = false; + fp = fopen("/proc/kallsyms", "re"); + if (fp == NULL) { + ERROR("Failed to open /proc/kallsyms: %s", strerror(errno)); + return -1; + } + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + for (num = getline(&buf, &len, fp); num != -1; num = getline(&buf, &len, fp)) { + char sym_addr[KALLSYMS_ITEM_MAX_LEN] = { 0 }; + char sym_type[KALLSYMS_ITEM_MAX_LEN] = { 0 }; + char sym_name[KALLSYMS_ITEM_MAX_LEN] = { 0 }; + + if (sscanf(buf, "%s %s %s", sym_addr, sym_type, sym_name) != 3) { + ERROR("sscanf buffer failed"); + ret = -1; + goto out; + } + + // Check for presence of symbol security_inode_copy_up. + if (strcmp(sym_name, "security_inode_copy_up") == 0) { + *supported = true; + goto out; + } + } + +out: + free(buf); + fclose(fp); + return ret; +} + +static int configure_kernel_security_support(const struct service_arguments *args) +{ + if (selinux_state_init() != 0) { + ERROR("Failed to init selinux state"); + return -1; + } + + if (args->json_confs->selinux_enabled) { + if (!selinux_get_enable()) { + WARN("iSulad could not enable SELinux on the host system"); + return 0; + } + + if (strcmp(args->json_confs->storage_driver, "overlay") == 0 || + strcmp(args->json_confs->storage_driver, "overlay2") == 0) { + // If driver is overlay or overlay2, make sure kernel + // supports selinux with overlay. + bool supported = false; + + if (overlay_supports_selinux(&supported)) { + return -1; + } + if (!supported) { + WARN("SELinux is not supported with the %s graph driver on this kernel", + args->json_confs->storage_driver); + } + } + } else { + selinux_set_disabled(); + } + return 0; +} + static int update_server_args(struct service_arguments *args) { int ret = 0; @@ -819,6 +895,13 @@ static int update_server_args(struct service_arguments *args) goto out; } + // Configure and validate the kernels security support. Note this is a Linux/FreeBSD + // operation only, so it is safe to pass *just* the runtime OS graphdriver. + if (configure_kernel_security_support(args)) { + ret = -1; + goto out; + } + #ifdef ENABLE_OCI_IMAGE args->driver = graphdriver_init(args->json_confs->storage_driver, args->json_confs->storage_opts, args->json_confs->storage_opts_len); diff --git a/src/config/isulad_config.c b/src/config/isulad_config.c index fbd0080..d5c3953 100644 --- a/src/config/isulad_config.c +++ b/src/config/isulad_config.c @@ -806,7 +806,7 @@ char *conf_get_isulad_log_gather_fifo_path() ERROR("Out of memory"); goto err_out; } - nret = snprintf(logfile, len, "%s%s", statedir, "LOG_GATHER_FIFO_NAME"); + nret = snprintf(logfile, len, "%s%s", statedir, LOG_GATHER_FIFO_NAME); if (nret < 0 || (size_t)nret >= len) { ERROR("Sprintf log file failed"); goto err_out; @@ -1206,6 +1206,28 @@ out: return result; } +char *conf_get_default_runtime() +{ + struct service_arguments *conf = NULL; + char *result = NULL; + + if (isulad_server_conf_rdlock()) { + ERROR("BUG conf_rdlock failed"); + return NULL; + } + + conf = conf_get_server_conf(); + if (conf == NULL || conf->json_confs == NULL) { + goto out; + } + + result = strings_to_lower(conf->json_confs->default_runtime); + +out: + (void)isulad_server_conf_unlock(); + return result; +} + bool conf_update_im_server_sock_addr(const char *new_sock_addr) { struct service_arguments *conf = NULL; @@ -1765,6 +1787,7 @@ int merge_json_confs_into_global(struct service_arguments *args) goto out; } + override_string_value(&args->json_confs->default_runtime, &tmp_json_confs->default_runtime); override_string_value(&args->json_confs->group, &tmp_json_confs->group); override_string_value(&args->json_confs->graph, &tmp_json_confs->graph); override_string_value(&args->json_confs->state, &tmp_json_confs->state); @@ -1790,6 +1813,9 @@ int merge_json_confs_into_global(struct service_arguments *args) override_string_value(&args->json_confs->cni_bin_dir, &tmp_json_confs->cni_bin_dir); override_string_value(&args->json_confs->cni_conf_dir, &tmp_json_confs->cni_conf_dir); + args->json_confs->runtimes = tmp_json_confs->runtimes; + tmp_json_confs->runtimes = NULL; + // Daemon storage-driver if (merge_storage_conf_into_global(args, tmp_json_confs)) { ret = -1; @@ -1836,6 +1862,8 @@ int merge_json_confs_into_global(struct service_arguments *args) goto out; } + args->json_confs->selinux_enabled = tmp_json_confs->selinux_enabled; + out: free(err); free_isulad_daemon_configs(tmp_json_confs); diff --git a/src/config/isulad_config.h b/src/config/isulad_config.h index 58ce068..e06559b 100644 --- a/src/config/isulad_config.h +++ b/src/config/isulad_config.h @@ -25,6 +25,7 @@ extern "C" { #endif #define DEFAULT_IM_SERVER_SOCK_ADDR "unix:///var/run/isulad/isula_image.sock" +#define DEFAULT_RUNTIME_NAME "lcr" struct isulad_conf { pthread_rwlock_t isulad_conf_rwlock; @@ -92,6 +93,8 @@ unsigned int conf_get_im_opt_timeout(); char *conf_get_im_server_sock_addr(); +char *conf_get_default_runtime(); + bool conf_update_im_server_sock_addr(const char *new_sock_addr); char *conf_get_graph_check_flag_file(); diff --git a/src/connect/client/grpc/client_base.h b/src/connect/client/grpc/client_base.h index 487016b..dabf0e4 100644 --- a/src/connect/client/grpc/client_base.h +++ b/src/connect/client/grpc/client_base.h @@ -113,16 +113,12 @@ public: context.set_deadline(tDeadline); } - // Set common name from cert.perm - char common_name_value[ClientBaseConstants::COMMON_NAME_LEN] = { 0 }; - ret = get_common_name_from_tls_cert(m_certFile.c_str(), common_name_value, - ClientBaseConstants::COMMON_NAME_LEN); - if (ret != 0) { - ERROR("Failed to get common name in: %s", m_certFile.c_str()); + // Set metadata for authorization + if (SetMetadataInfo(context) != 0) { + ERROR("Failed to set metadata info for authorization"); + response->cc = ISULAD_ERR_INPUT; return -1; } - context.AddMetadata("username", std::string(common_name_value, strlen(common_name_value))); - context.AddMetadata("tls_mode", m_tlsMode); ret = request_to_grpc(request, &req); if (ret != 0) { @@ -175,7 +171,7 @@ protected: return Status::OK; }; - static std::string ReadTextFile(const char *file) + std::string ReadTextFile(const char *file) { char *real_file = verify_file_and_get_real_path(file); if (real_file == nullptr) { @@ -195,6 +191,22 @@ protected: return ss.str(); } + int SetMetadataInfo(ClientContext &context) + { + // Set common name from cert.perm + char common_name_value[ClientBaseConstants::COMMON_NAME_LEN] = { 0 }; + int ret = get_common_name_from_tls_cert(m_certFile.c_str(), common_name_value, + ClientBaseConstants::COMMON_NAME_LEN); + if (ret != 0) { + ERROR("Failed to get common name in: %s", m_certFile.c_str()); + return -1; + } + context.AddMetadata("username", std::string(common_name_value, strlen(common_name_value))); + context.AddMetadata("tls_mode", m_tlsMode); + + return 0; + } + std::unique_ptr stub_; std::string m_tlsMode { ClientBaseConstants::TLS_OFF }; std::string m_certFile { "" }; diff --git a/src/connect/client/grpc/grpc_containers_client.cc b/src/connect/client/grpc/grpc_containers_client.cc index 4a3a53f..6050ba6 100644 --- a/src/connect/client/grpc/grpc_containers_client.cc +++ b/src/connect/client/grpc/grpc_containers_client.cc @@ -230,10 +230,6 @@ public: { int nret = -1; - if (req.runtime().empty()) { - ERROR("Missing runtime in the request"); - return nret; - } if (req.rootfs().empty() && req.image().empty()) { ERROR("Missing container rootfs or image arguments in the request"); return nret; @@ -1745,7 +1741,13 @@ public: Event event; ClientContext context; Status status; - container_events_format_t isula_event; + container_events_format_t *isula_event = nullptr; + + if (SetMetadataInfo(context)) { + ERROR("Failed to set metadata info for authorization"); + response->cc = ISULAD_ERR_INPUT; + return -1; + } ret = events_request_to_grpc(request, &req); if (ret != 0) { @@ -1756,10 +1758,18 @@ public: std::unique_ptr> reader(stub_->Events(&context, req)); while (reader->Read(&event)) { - event_from_grpc(&isula_event, &event); - if (request->cb != nullptr) { - request->cb(&isula_event); + isula_event = (container_events_format_t *)util_common_calloc_s(sizeof(container_events_format_t)); + if (isula_event == nullptr) { + ERROR("Out of memory"); + response->server_errono = ISULAD_ERR_EXEC; + return -1; } + event_from_grpc(isula_event, &event); + if (request->cb != nullptr) { + request->cb(isula_event); + } + container_events_format_free(isula_event); + isula_event = nullptr; } status = reader->Finish(); if (!status.ok()) { @@ -1793,20 +1803,25 @@ private: void event_from_grpc(container_events_format_t *event, Event *gevent) { (void)memset(event, 0, sizeof(*event)); - if (!gevent->id().empty()) { - event->id = (char *)gevent->id().c_str(); - } - - event->has_type = true; - event->type = (container_events_type_t)((int)gevent->type()); - event->has_pid = (int)gevent->pid() != -1; - event->pid = (uint32_t)gevent->pid(); - event->has_exit_status = true; - event->exit_status = gevent->exit_status(); if (gevent->has_timestamp()) { protobuf_timestamp_from_grpc(&event->timestamp, gevent->timestamp()); } + + if (!gevent->opt().empty()) { + event->opt = util_strdup_s(gevent->opt().c_str()); + } + + if (!gevent->id().empty()) { + event->id = util_strdup_s(gevent->id().c_str()); + } + + google::protobuf::Map map = gevent->annotations(); + for (auto iter = map.cbegin(); iter != map.cend(); ++iter) { + std::string anno = iter->first + "=" + iter->second; + (void)util_array_append(&event->annotations, anno.c_str()); + event->annotations_len++; + } } int events_request_to_grpc(const struct isula_events_request *request, EventsRequest *grequest) diff --git a/src/connect/client/grpc/grpc_isula_image_client.cc b/src/connect/client/grpc/grpc_isula_image_client.cc index 236fe10..a7f6c60 100644 --- a/src/connect/client/grpc/grpc_isula_image_client.cc +++ b/src/connect/client/grpc/grpc_isula_image_client.cc @@ -119,6 +119,7 @@ public: explicit ISulaContainerPrepare(void *args) : ClientBase(args) { } + ~ISulaContainerPrepare() = default; int request_to_grpc(const isula_prepare_request *req, isula::ContainerPrepareRequest *grequest) override { @@ -184,6 +185,8 @@ public: { } + ~ISulaContainerRemove() = default; + int request_to_grpc(const isula_remove_request *req, isula::ContainerRemoveRequest *grequest) override { if (req == nullptr) { @@ -227,6 +230,8 @@ public: { } + ~ISulaContainerMount() = default; + int request_to_grpc(const isula_mount_request *req, isula::ContainerMountRequest *grequest) override { if (req == nullptr) { @@ -270,6 +275,8 @@ public: { } + ~ISulaContainerUmount() = default; + int request_to_grpc(const isula_umount_request *req, isula::ContainerUmountRequest *grequest) override { if (req == nullptr) { @@ -314,6 +321,8 @@ public: { } + ~ISulaContainersList() = default; + int request_to_grpc(const isula_containers_list_request *req, isula::ListContainersRequest *grequest) override { if (req == nullptr) { @@ -359,6 +368,8 @@ public: { } + ~ISulaImagePull() = default; + int request_to_grpc(const isula_pull_request *req, isula::PullImageRequest *grequest) override { if (req == nullptr) { @@ -437,6 +448,7 @@ public: explicit ISulaImageStatus(void *args) : ClientBase(args) { } + ~ISulaImageStatus() = default; int request_to_grpc(const isula_status_request *req, isula::ImageStatusRequest *grequest) override { @@ -508,6 +520,7 @@ public: explicit ISulaListImages(void *args) : ClientBase(args) { } + ~ISulaListImages() = default; int request_to_grpc(const isula_list_request *req, isula::ListImagesRequest *grequest) override { @@ -574,6 +587,7 @@ public: explicit ISulaRmi(void *args) : ClientBase(args) { } + ~ISulaRmi() = default; int request_to_grpc(const isula_rmi_request *req, isula::RemoveImageRequest *grequest) override { @@ -625,6 +639,7 @@ public: explicit ISulaLoad(void *args) : ClientBase(args) { } + ~ISulaLoad() = default; int request_to_grpc(const isula_load_request *req, isula::LoadImageRequest *grequest) override { @@ -682,6 +697,7 @@ public: explicit ISulaLogin(void *args) : ClientBase(args) { } + ~ISulaLogin() = default; int request_to_grpc(const isula_login_request *req, isula::LoginRequest *grequest) override { @@ -736,6 +752,7 @@ public: explicit ISulaLogout(void *args) : ClientBase(args) { } + ~ISulaLogout() = default; int request_to_grpc(const isula_logout_request *req, isula::LogoutRequest *grequest) override { @@ -780,6 +797,7 @@ public: explicit ISulaExport(void *args) : ClientBase(args) { } + ~ISulaExport() = default; int request_to_grpc(const isula_export_request *req, isula::ContainerExportRequest *grequest) override { @@ -835,6 +853,7 @@ public: explicit ISulaStorageStatus(void *args) : ClientBase(args) { } + ~ISulaStorageStatus() = default; int response_from_grpc(isula::GraphdriverStatusResponse *gresp, isula_storage_status_response *resp) override { @@ -863,6 +882,7 @@ public: explicit ISulaContainerFsUsage(void *args) : ClientBase(args) { } + ~ISulaContainerFsUsage() = default; int request_to_grpc(const isula_container_fs_usage_request *req, isula::ContainerFsUsageRequest *grequest) override { @@ -912,6 +932,7 @@ public: explicit ISulaImageFsInfo(void *args) : ClientBase(args) { } + ~ISulaImageFsInfo() = default; int response_from_grpc(isula::ImageFsInfoResponse *gresp, isula_image_fs_info_response *resp) override { @@ -993,6 +1014,7 @@ public: explicit ISulaHealthCheck(void *args) : ClientBase(args) { } + ~ISulaHealthCheck() = default; int response_from_grpc(isula::HealthCheckResponse *gresp, isula_health_check_response *resp) override { diff --git a/src/connect/client/rest/rest_containers_client.c b/src/connect/client/rest/rest_containers_client.c index 26d8bdb..09d7135 100644 --- a/src/connect/client/rest/rest_containers_client.c +++ b/src/connect/client/rest/rest_containers_client.c @@ -330,7 +330,7 @@ static int unpack_create_response(const struct parsed_http_message *message, voi response->id = util_strdup_s(cresponse->id); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -364,7 +364,7 @@ static int unpack_start_response(const struct parsed_http_message *message, void start_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -455,7 +455,7 @@ static int unpack_list_response(const struct parsed_http_message *message, void response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } if (unpack_container_info_for_list_response(cresponse, response)) { @@ -493,7 +493,7 @@ static int unpack_attach_response(const struct parsed_http_message *message, voi attach_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -527,7 +527,7 @@ static int unpack_resume_response(const struct parsed_http_message *message, voi resume_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -562,7 +562,7 @@ static int unpack_wait_response(const struct parsed_http_message *message, void response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -830,7 +830,7 @@ static int unpack_stop_response(const struct parsed_http_message *message, void stop_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -930,7 +930,7 @@ static int unpack_restart_response(const struct parsed_http_message *message, vo response->errmsg = util_strdup_s(cres->errmsg); } ret = (cres->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -1043,7 +1043,7 @@ static int unpack_update_response(const struct parsed_http_message *message, voi update_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -1150,7 +1150,7 @@ static int unpack_version_response(const struct parsed_http_message *message, vo version_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -1249,7 +1249,7 @@ static int unpack_pause_response(const struct parsed_http_message *message, void pause_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -1349,7 +1349,7 @@ static int unpack_kill_response(const struct parsed_http_message *message, void kill_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -1449,7 +1449,7 @@ static int unpack_remove_response(const struct parsed_http_message *message, voi delete_response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -1554,7 +1554,7 @@ static int unpack_inspect_response(const struct parsed_http_message *message, vo response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -1704,7 +1704,7 @@ static int unpack_exec_response(const struct parsed_http_message *message, void response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } diff --git a/src/connect/client/rest/rest_images_client.c b/src/connect/client/rest/rest_images_client.c index 90ca4db..aaa71bc 100644 --- a/src/connect/client/rest/rest_images_client.c +++ b/src/connect/client/rest/rest_images_client.c @@ -174,7 +174,7 @@ static int unpack_image_list_response(const struct parsed_http_message *message, response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -213,7 +213,7 @@ static int unpack_image_load_response(const struct parsed_http_message *message, c_load_response->errmsg = util_strdup_s(load_response->errmsg); } ret = (load_response->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -279,7 +279,7 @@ static int unpack_image_delete_response(const struct parsed_http_message *messag c_rmi_response->errmsg = util_strdup_s(delete_response->errmsg); } ret = (delete_response->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } @@ -416,7 +416,7 @@ static int unpack_inspect_response(const struct parsed_http_message *message, vo response->errmsg = util_strdup_s(cresponse->errmsg); } ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1; - if (message->status_code == EVHTP_RES_SERVERR) { + if (message->status_code == RESTFUL_RES_SERVERR) { ret = -1; } diff --git a/src/connect/service/grpc/grpc_containers_service.cc b/src/connect/service/grpc/grpc_containers_service.cc index 39c7264..1dfe1ac 100644 --- a/src/connect/service/grpc/grpc_containers_service.cc +++ b/src/connect/service/grpc/grpc_containers_service.cc @@ -41,28 +41,37 @@ void protobuf_timestamp_from_grpc(types_timestamp_t *timestamp, const Timestamp timestamp->nanos = gtimestamp.nanos(); } -void event_to_grpc(const struct isulad_events_format *event, Event *gevent) +int event_to_grpc(const struct isulad_events_format *event, Event *gevent) { gevent->Clear(); - if (event->id != nullptr) { - gevent->set_id(event->id); - } - - if (event->has_type != 0) { - gevent->set_type((EventType)event->type); - } - if (event->has_pid != 0) { - gevent->set_pid((int32_t)(event->pid)); - } else { - gevent->set_pid(-1); - } - if (event->has_exit_status != 0) { - gevent->set_exit_status(event->exit_status); - } if (event->timestamp.has_seconds != 0 || event->timestamp.has_nanos != 0) { protobuf_timestamp_to_grpc((const types_timestamp_t *)(&event->timestamp), gevent->mutable_timestamp()); } + + if (event->opt != nullptr) { + gevent->set_opt(event->opt); + } + + if (event->id != nullptr) { + gevent->set_id(event->id); + } + + if (event->annotations_len != 0 && event->annotations != nullptr) { + google::protobuf::Map *map = gevent->mutable_annotations(); + for (size_t i {0}; i < event->annotations_len; i++) { + char **elems = util_string_split_n(event->annotations[i], '=', 2); + if (util_array_len((const char **)elems) != 2) { + ERROR("Invalid annotation info"); + util_free_array(elems); + return -1; + } + (*map)[elems[0]] = elems[1]; + util_free_array(elems); + } + } + + return 0; } void copy_from_container_response_to_grpc(const struct isulad_copy_from_container_response *copy, @@ -93,7 +102,9 @@ bool grpc_event_write_function(void *writer, void *data) struct isulad_events_format *event = (struct isulad_events_format *)data; ServerWriter *gwriter = (ServerWriter *)writer; Event gevent; - event_to_grpc(event, &gevent); + if (event_to_grpc(event, &gevent) != 0) { + return false; + } return gwriter->Write(gevent); } @@ -1258,6 +1269,7 @@ Status ContainerServiceImpl::Events(ServerContext *context, const EventsRequest if (ret != 0) { return Status(StatusCode::INTERNAL, "Failed to execute events callback"); } + return Status::OK; } diff --git a/src/connect/service/grpc/runtime_runtime_service.cc b/src/connect/service/grpc/runtime_runtime_service.cc index 51f0cce..62e96a1 100644 --- a/src/connect/service/grpc/runtime_runtime_service.cc +++ b/src/connect/service/grpc/runtime_runtime_service.cc @@ -194,7 +194,7 @@ grpc::Status RuntimeRuntimeServiceImpl::RunPodSandbox( runtime::v1alpha2::RunPodSandboxResponse *reply) { Errors error; - std::string responseID = rService.RunPodSandbox(request->config(), error); + std::string responseID = rService.RunPodSandbox(request->config(), request->runtime_handler(), error); if (!error.Empty() || responseID.empty()) { return grpc::Status(grpc::StatusCode::UNKNOWN, error.GetMessage()); } diff --git a/src/connect/service/rest/rest_containers_service.c b/src/connect/service/rest/rest_containers_service.c index 30ac093..ed6c1ce 100644 --- a/src/connect/service/rest/rest_containers_service.c +++ b/src/connect/service/rest/rest_containers_service.c @@ -208,14 +208,14 @@ static void evhtp_send_create_repsponse(evhtp_request_t *req, container_create_r if (response == NULL) { ERROR("Failed to generate create response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_create_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Create: failed to generate request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -345,14 +345,14 @@ static void evhtp_send_start_repsponse(evhtp_request_t *req, container_start_res if (response == NULL) { ERROR("Failed to generate start response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_start_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate start request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -373,14 +373,14 @@ static void evhtp_send_list_repsponse(evhtp_request_t *req, container_list_respo if (response == NULL) { ERROR("Failed to generate inspect response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_list_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate list request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -402,7 +402,7 @@ static void evhtp_send_wait_repsponse(evhtp_request_t *req, container_wait_respo responsedata = container_wait_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate wait request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -424,26 +424,26 @@ static void rest_create_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.create == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceCreate); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.create(crequest, &cresponse); - evhtp_send_create_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_create_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_create_response(cresponse); free_container_create_request(crequest); @@ -459,26 +459,26 @@ static void rest_start_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.start == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceStart); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.start(crequest, &cresponse, -1, NULL, NULL); - evhtp_send_start_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_start_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_start_request(crequest); free_container_start_response(cresponse); @@ -494,26 +494,26 @@ static void rest_wait_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.wait == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceWait); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.wait(crequest, &cresponse); - evhtp_send_wait_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_wait_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_wait_request(crequest); free_container_wait_response(cresponse); @@ -528,14 +528,14 @@ static void evhtp_send_stop_repsponse(evhtp_request_t *req, container_stop_respo if (response == NULL) { ERROR("Failed to generate stop response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_stop_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate stop request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -557,26 +557,26 @@ static void rest_stop_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.stop == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceStop); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.stop(crequest, &cresponse); - evhtp_send_stop_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_stop_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_stop_response(cresponse); free_container_stop_request(crequest); @@ -591,13 +591,13 @@ static void evhtp_send_restart_response(evhtp_request_t *req, container_restart_ if (response == NULL) { ERROR("Failed to generate restart response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_restart_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate restart response json: %s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -618,27 +618,27 @@ static void rest_restart_cb(evhtp_request_t *req, void *arg) container_restart_response *cresponse = NULL; if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.restart == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceRestart); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.restart(crequest, &cresponse); - evhtp_send_restart_response(req, cresponse, EVHTP_RES_OK); + evhtp_send_restart_response(req, cresponse, RESTFUL_RES_OK); out: free_container_restart_request(crequest); free_container_restart_response(cresponse); @@ -654,7 +654,7 @@ static void evhtp_send_version_repsponse(evhtp_request_t *req, container_version responsedata = container_version_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate version request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -676,26 +676,26 @@ static void rest_version_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.version == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceVersion); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.version(crequest, &cresponse); - evhtp_send_version_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_version_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_version_request(crequest); free_container_version_response(cresponse); @@ -710,14 +710,14 @@ static void evhtp_send_update_repsponse(evhtp_request_t *req, container_update_r if (response == NULL) { ERROR("Invalid NULL response"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_update_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate update request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -739,25 +739,25 @@ static void rest_update_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.update == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&container_req, ContainerServiceUpdate); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.update(container_req, &container_res); - evhtp_send_update_repsponse(req, container_res, EVHTP_RES_OK); + evhtp_send_update_repsponse(req, container_res, RESTFUL_RES_OK); out: free_container_update_request(container_req); @@ -773,13 +773,13 @@ static void evhtp_send_kill_repsponse(evhtp_request_t *req, container_kill_respo if (response == NULL) { ERROR("Failed to generate kill response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_kill_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate kill request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -801,26 +801,26 @@ static void rest_kill_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.kill == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceKill); if (tret < 0) { ERROR("bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.kill(crequest, &cresponse); - evhtp_send_kill_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_kill_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_kill_request(crequest); free_container_kill_response(cresponse); @@ -836,14 +836,14 @@ static void evhtp_send_container_inspect_repsponse(evhtp_request_t *req, contain if (response == NULL) { ERROR("Failed to generate inspect response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_inspect_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate inspect request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -865,26 +865,26 @@ static void rest_container_inspect_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.inspect == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceInspect); if (tret < 0) { ERROR("bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.inspect(crequest, &cresponse); - evhtp_send_container_inspect_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_container_inspect_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_inspect_request(crequest); free_container_inspect_response(cresponse); @@ -899,14 +899,14 @@ static void evhtp_send_exec_repsponse(evhtp_request_t *req, container_exec_respo if (response == NULL) { ERROR("Failed to generate exec response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_exec_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate exec request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -928,26 +928,26 @@ static void rest_exec_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || !cb->container.exec) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceExec); if (tret < 0) { ERROR("bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.exec(crequest, &cresponse, -1, NULL); - evhtp_send_exec_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_exec_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_exec_request(crequest); free_container_exec_response(cresponse); @@ -962,13 +962,13 @@ static void evhtp_send_remove_repsponse(evhtp_request_t *req, container_delete_r if (response == NULL) { ERROR("Failed to generate remove response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = container_delete_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate remove request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -990,26 +990,26 @@ static void rest_remove_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.remove == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceRemove); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.remove(crequest, &cresponse); - evhtp_send_remove_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_remove_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_delete_request(crequest); free_container_delete_response(cresponse); @@ -1025,26 +1025,26 @@ static void rest_list_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->container.list == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = action_request_from_rest(req, (void **)&crequest, ContainerServiceList); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->container.list(crequest, &cresponse); - evhtp_send_list_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_list_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_container_list_request(crequest); free_container_list_response(cresponse); diff --git a/src/connect/service/rest/rest_images_service.c b/src/connect/service/rest/rest_images_service.c index 5a90740..d6cb37f 100644 --- a/src/connect/service/rest/rest_images_service.c +++ b/src/connect/service/rest/rest_images_service.c @@ -78,7 +78,7 @@ static void evhtp_send_image_load_repsponse(evhtp_request_t *req, responsedata = image_load_image_response_generate_json(response, NULL, &err); if (responsedata == NULL) { ERROR("Load: failed to generate request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } evhtp_send_response(req, responsedata, rescode); @@ -126,7 +126,7 @@ static void evhtp_send_image_list_repsponse(evhtp_request_t *req, responsedata = image_list_images_response_generate_json(response, NULL, &err); if (responsedata == NULL) { ERROR("List: failed to generate request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } evhtp_send_response(req, responsedata, rescode); @@ -198,7 +198,7 @@ static void evhtp_send_image_delete_repsponse(evhtp_request_t *req, } ERROR("Delete: failed to generate request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); out: free(responsedata); free(err); @@ -259,14 +259,14 @@ static void evhtp_send_image_inspect_repsponse(evhtp_request_t *req, if (response == NULL) { ERROR("Failed to generate inspect response info"); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } responsedata = image_inspect_response_generate_json(response, &ctx, &err); if (responsedata == NULL) { ERROR("Failed to generate inspect request json:%s", err); - evhtp_send_reply(req, EVHTP_RES_ERROR); + evhtp_send_reply(req, RESTFUL_RES_ERROR); goto out; } @@ -288,26 +288,26 @@ static void rest_image_load_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->image.load == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = image_load_request_from_rest(req, &crequest); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->image.load(crequest, &cresponse); - evhtp_send_image_load_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_image_load_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_image_load_image_request(crequest); free_image_load_image_response(cresponse); @@ -323,26 +323,26 @@ static void rest_image_list_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->image.list == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = image_list_request_from_rest(req, &crequest); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->image.list(crequest, &cresponse); - evhtp_send_image_list_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_image_list_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_image_list_images_request(crequest); free_image_list_images_response(cresponse); @@ -358,26 +358,26 @@ static void rest_image_delete_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->image.remove == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = image_delete_request_from_rest(req, &crequest); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->image.remove(crequest, &cresponse); - evhtp_send_image_delete_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_image_delete_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_image_delete_image_request(crequest); free_image_delete_image_response(cresponse); @@ -393,26 +393,26 @@ static void rest_image_inspect_cb(evhtp_request_t *req, void *arg) // only deal with POST request if (evhtp_request_get_method(req) != htp_method_POST) { - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } cb = get_service_callback(); if (cb == NULL || cb->image.inspect == NULL) { ERROR("Unimplemented callback"); - evhtp_send_reply(req, EVHTP_RES_NOTIMPL); + evhtp_send_reply(req, RESTFUL_RES_NOTIMPL); return; } tret = image_inspect_request_from_rest(req, &crequest); if (tret < 0) { ERROR("Bad request"); - evhtp_send_reply(req, EVHTP_RES_SERVERR); + evhtp_send_reply(req, RESTFUL_RES_SERVERR); goto out; } (void)cb->image.inspect(crequest, &cresponse); - evhtp_send_image_inspect_repsponse(req, cresponse, EVHTP_RES_OK); + evhtp_send_image_inspect_repsponse(req, cresponse, RESTFUL_RES_OK); out: free_image_inspect_request(crequest); free_image_inspect_response(cresponse); diff --git a/src/connect/service/rest/rest_service_common.h b/src/connect/service/rest/rest_service_common.h index 2192c3a..f007c21 100644 --- a/src/connect/service/rest/rest_service_common.h +++ b/src/connect/service/rest/rest_service_common.h @@ -17,6 +17,8 @@ #include +#include "rest_common.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/src/constants.h b/src/constants.h index 973b006..55fb03c 100644 --- a/src/constants.h +++ b/src/constants.h @@ -46,6 +46,8 @@ #define DEBUG_DIRECTORY_MODE 0750 +#define NETWORK_MOUNT_FILE_MODE 0644 + #define ISULAD_CONFIG "/etc/isulad" #define ISULAD_DAEMON_JSON_CONF_FILE ISULAD_CONFIG "/daemon.json" diff --git a/src/container_def.c b/src/container_def.c index 0111e95..32d689c 100644 --- a/src/container_def.c +++ b/src/container_def.c @@ -32,3 +32,27 @@ void container_cgroup_resources_free(container_cgroup_resources_t *cr) free(cr); } +void container_events_format_free(container_events_format_t *value) +{ + size_t i; + + if (value == NULL) { + return; + } + + free(value->opt); + value->opt = NULL; + + free(value->id); + value->id = NULL; + + for (i = 0; i < value->annotations_len; i++) { + free(value->annotations[i]); + value->annotations[i] = NULL; + } + + free(value->annotations); + value->annotations = NULL; + + free(value); +} \ No newline at end of file diff --git a/src/container_def.h b/src/container_def.h index c18c2a8..16a589f 100644 --- a/src/container_def.h +++ b/src/container_def.h @@ -40,7 +40,7 @@ extern "C" { #define SECCOMP_DEFAULT_PATH "/etc/isulad/seccomp_default.json" #endif #ifndef OCI_VERSION -#define OCI_VERSION "1.0.0-rc5-dev" +#define OCI_VERSION "1.0.1" #endif typedef enum { @@ -55,12 +55,36 @@ typedef enum { EVENTS_TYPE_THAWED = 8, EVENTS_TYPE_OOM = 9, EVENTS_TYPE_CREATE = 10, - EVENTS_TYPE_START = 11, - EVENTS_TYPE_EXEC_ADDED = 12, - EVENTS_TYPE_PAUSED1 = 13, - EVENTS_TYPE_MAX_STATE = 14 + EVENTS_TYPE_START, + EVENTS_TYPE_RESTART, + EVENTS_TYPE_STOP, + EVENTS_TYPE_EXEC_CREATE, + EVENTS_TYPE_EXEC_START, + EVENTS_TYPE_EXEC_DIE, + EVENTS_TYPE_ATTACH, + EVENTS_TYPE_KILL, + EVENTS_TYPE_TOP, + EVENTS_TYPE_RENAME, + EVENTS_TYPE_ARCHIVE_PATH, + EVENTS_TYPE_EXTRACT_TO_DIR, + EVENTS_TYPE_UPDATE, + EVENTS_TYPE_PAUSE, + EVENTS_TYPE_UNPAUSE, + EVENTS_TYPE_EXPORT, + EVENTS_TYPE_RESIZE, + EVENTS_TYPE_PAUSED1, + EVENTS_TYPE_MAX_STATE } container_events_type_t; +typedef enum { + EVENTS_TYPE_IMAGE_LOAD = 0, + EVENTS_TYPE_IMAGE_REMOVE, + EVENTS_TYPE_IMAGE_PULL, + EVENTS_TYPE_IMAGE_LOGIN, + EVENTS_TYPE_IMAGE_LOGOUT, + EVENTS_TYPE_IMAGE_MAX_STATE +} image_events_type_t; + typedef enum { CONTAINER_STATUS_UNKNOWN = 0, CONTAINER_STATUS_CREATED = 1, @@ -73,10 +97,16 @@ typedef enum { } Container_Status; typedef enum { - STOPPED, STARTING, RUNNING, STOPPING, - ABORTING, FREEZING, FROZEN, THAWED, MAX_STATE + EXIT, STOPPED, STARTING, RUNNING, STOPPING, ABORTING, FREEZING, + FROZEN, THAWED, OOM, CREATE, START, RESTART, STOP, EXEC_CREATE, EXEC_START, EXEC_DIE, ATTACH, + KILL, TOP, RENAME, ARCHIVE_PATH, EXTRACT_TO_DIR, UPDATE, PAUSE, UNPAUSE, EXPORT, RESIZE, PAUSED1, MAX_STATE, } runtime_state_t; +typedef enum { + IM_LOAD, IM_REMOVE, IM_PULL, IM_LOGIN, IM_LOGOUT +} image_state_t; + + typedef enum { HEALTH_SERVING_STATUS_UNKNOWN = 0, HEALTH_SERVING_STATUS_SERVING = 1, @@ -100,6 +130,11 @@ typedef enum { WAIT_CONDITION_REMOVED = 1 } wait_condition_t; +typedef enum { + CONTAINER_EVENT, + IMAGE_EVENT +} msg_event_type_t; + typedef struct container_cgroup_resources { uint16_t blkio_weight; int64_t cpu_shares; @@ -116,21 +151,20 @@ typedef struct container_cgroup_resources { int64_t pids_limit; int64_t files_limit; int64_t oom_score_adj; + int64_t swappiness; } container_cgroup_resources_t; typedef struct container_events_format { - char *id; - uint32_t has_type; - container_events_type_t type; - uint32_t has_pid; - uint32_t pid; - uint32_t has_exit_status; - uint32_t exit_status; types_timestamp_t timestamp; + char *opt; + char *id; + char **annotations; + char annotations_len; } container_events_format_t; void container_cgroup_resources_free(container_cgroup_resources_t *cr); +void container_events_format_free(container_events_format_t *value); typedef void (*container_events_callback_t)(const container_events_format_t *event); diff --git a/src/contrib/config/config.json b/src/contrib/config/config.json index 9a9ec87..59c1bfb 100644 --- a/src/contrib/config/config.json +++ b/src/contrib/config/config.json @@ -1,5 +1,5 @@ { - "ociVersion": "1.0.0-rc5-dev", + "ociVersion": "1.0.1", "process": { "terminal": true, "consoleSize": { @@ -96,18 +96,6 @@ "ro" ] }, - { - "destination": "/dev/shm", - "type": "tmpfs", - "source": "shm", - "options": [ - "nosuid", - "noexec", - "nodev", - "mode=1777", - "size=65536k" - ] - }, { "destination": "/sys/fs/cgroup", "type": "cgroup", diff --git a/src/contrib/config/daemon.json b/src/contrib/config/daemon.json index 7baea20..dfd2a63 100644 --- a/src/contrib/config/daemon.json +++ b/src/contrib/config/daemon.json @@ -1,5 +1,6 @@ { "group": "isulad", + "default-runtime": "lcr", "graph": "/var/lib/isulad", "state": "/var/run/isulad", "engine": "lcr", diff --git a/src/contrib/config/systemcontainer_config.json b/src/contrib/config/systemcontainer_config.json index 3d2bd89..dfef975 100644 --- a/src/contrib/config/systemcontainer_config.json +++ b/src/contrib/config/systemcontainer_config.json @@ -1,5 +1,5 @@ { - "ociVersion": "1.0.0-rc5-dev", + "ociVersion": "1.0.1", "process": { "terminal": true, "consoleSize": { @@ -96,18 +96,6 @@ "ro" ] }, - { - "destination": "/dev/shm", - "type": "tmpfs", - "source": "shm", - "options": [ - "nosuid", - "noexec", - "nodev", - "mode=1777", - "size=65536k" - ] - }, { "destination": "/sys/fs/cgroup", "type": "cgroup", diff --git a/src/cutils/utils.c b/src/cutils/utils.c index 1e30aaf..092f72e 100644 --- a/src/cutils/utils.c +++ b/src/cutils/utils.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/src/cutils/utils_file.c b/src/cutils/utils_file.c index 95df5ba..d63dc3a 100644 --- a/src/cutils/utils_file.c +++ b/src/cutils/utils_file.c @@ -552,7 +552,7 @@ char *util_full_file_digest(const char *filename) return full_digest; } -static char *util_path_dir(const char *path) +char *util_path_dir(const char *path) { char *dir = NULL; int len = 0; @@ -822,7 +822,7 @@ free_out: return ret; } -int util_write_file(const char *fname, const char *content, size_t content_len) +int util_write_file(const char *fname, const char *content, size_t content_len, mode_t mode) { int ret = 0; int dst_fd = -1; @@ -834,7 +834,7 @@ int util_write_file(const char *fname, const char *content, size_t content_len) if (content == NULL || content_len == 0) { return 0; } - dst_fd = util_open(fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_SECURE_FILE_MODE); + dst_fd = util_open(fname, O_WRONLY | O_CREAT | O_TRUNC, mode); if (dst_fd < 0) { ERROR("Creat file: %s, failed: %s", fname, strerror(errno)); ret = -1; @@ -877,7 +877,7 @@ char *verify_file_and_get_real_path(const char *file) return util_strdup_s(resolved_path); } -int util_copy_file(const char *src_file, const char *dst_file) +int util_copy_file(const char *src_file, const char *dst_file, mode_t mode) { #define BUFSIZE 4096 int ret = 0; @@ -902,7 +902,7 @@ int util_copy_file(const char *src_file, const char *dst_file) ret = -1; goto free_out; } - dst_fd = util_open(dst_file, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_SECURE_FILE_MODE); + dst_fd = util_open(dst_file, O_WRONLY | O_CREAT | O_TRUNC, mode); if (dst_fd < 0) { ERROR("Creat file: %s, failed: %s", dst_file, strerror(errno)); ret = -1; diff --git a/src/cutils/utils_file.h b/src/cutils/utils_file.h index 78ae5cd..83aead7 100644 --- a/src/cutils/utils_file.h +++ b/src/cutils/utils_file.h @@ -55,6 +55,8 @@ FILE *util_fopen(const char *filename, const char *mode); char *util_full_file_digest(const char *filename); +char *util_path_dir(const char *path); + char *util_add_path(const char *path, const char *name); char *util_read_text_file(const char *path); @@ -67,11 +69,11 @@ int util_file2str(const char *filename, char *buf, size_t len); char *look_path(const char *file, char **err); -int util_write_file(const char *fname, const char *content, size_t content_len); +int util_write_file(const char *fname, const char *content, size_t content_len, mode_t mode); char *verify_file_and_get_real_path(const char *file); -int util_copy_file(const char *src_file, const char *dst_file); +int util_copy_file(const char *src_file, const char *dst_file, mode_t mode); #ifdef __cplusplus } diff --git a/src/cutils/utils_string.c b/src/cutils/utils_string.c index 27136bb..2ba3d1d 100644 --- a/src/cutils/utils_string.c +++ b/src/cutils/utils_string.c @@ -79,6 +79,18 @@ bool strings_contains_any(const char *str, const char *substr) return false; } +bool strings_contains_word(const char *str, const char *substr) +{ + if (str == NULL || substr == NULL) { + return false; + } + + if (strcasestr(str, substr) != NULL) { + return true; + } + return false; +} + int strings_count(const char *str, unsigned char c) { size_t i = 0; @@ -271,7 +283,8 @@ int util_parse_percent_string(const char *s, long *converted) { char *dup = NULL; - if (s == NULL || converted == NULL || s[0] == 0 || strlen(s) < 2 || s[strlen(s) - 1] != '%') { + if (s == NULL || converted == NULL || s[0] == 0 || strlen(s) < 2 || s[strlen(s) - 1] != '%' || + strspn(s, "0123456789%") != strlen(s)) { return -EINVAL; } dup = util_strdup_s(s); @@ -282,7 +295,7 @@ int util_parse_percent_string(const char *s, long *converted) *converted = strtol(dup, NULL, 10); if ((errno == ERANGE && (*converted == LONG_MAX || *converted == LONG_MIN)) || - (errno != 0 && *converted == 0) || *converted < 0 || *converted >= 100) { + (errno != 0 && *converted == 0) || *converted < 0 || *converted > 100) { free(dup); return -EINVAL; } @@ -369,6 +382,49 @@ err_out: return NULL; } +char **util_string_split_n(const char *src, char sep, size_t n) +{ + char **res_array = NULL; + const char *index = NULL; + char *token = NULL; + char *str = NULL; + size_t count = 0; + int tmp_errno; + + if (src == NULL || n == 0) { + return NULL; + } + + if (src[0] == '\0') { + return make_empty_array(); + } + str = util_strdup_s(src); + index = str; + for (token = strchr(index, sep); token != NULL; token = strchr(index, sep)) { + count++; + if (count >= n) { + break; + } + *token = '\0'; + if (util_array_append(&res_array, index) != 0) { + goto err_out; + } + index = token + 1; + } + if (util_array_append(&res_array, index) != 0) { + goto err_out; + } + free(str); + return res_array; + +err_out: + tmp_errno = errno; + free(str); + util_free_array(res_array); + errno = tmp_errno; + return NULL; +} + char **util_string_split(const char *src_str, char _sep) { char *token = NULL; diff --git a/src/cutils/utils_string.h b/src/cutils/utils_string.h index d869936..65966d8 100644 --- a/src/cutils/utils_string.h +++ b/src/cutils/utils_string.h @@ -25,6 +25,8 @@ extern "C" { bool strings_contains_any(const char *str, const char *substr); +bool strings_contains_word(const char *str, const char *substr); + int strings_count(const char *str, unsigned char c); bool strings_in_slice(const char **strarray, size_t alen, const char *str); @@ -45,6 +47,8 @@ char **util_string_split(const char *src_str, char _sep); // note that every delimiter bytes is considered to be a single delimiter char **util_string_split_multi(const char *src_str, char delim); +char **util_string_split_n(const char *src_str, char delim, size_t n); + const char *str_skip_str(const char *str, const char *skip); char *util_string_delchar(const char *ss, unsigned char c); diff --git a/src/cutils/utils_verify.c b/src/cutils/utils_verify.c index 562a942..01fec49 100644 --- a/src/cutils/utils_verify.c +++ b/src/cutils/utils_verify.c @@ -274,7 +274,7 @@ bool util_valid_runtime_name(const char *name) return false; } - return strcasecmp(name, "lcr") == 0; + return true; } bool util_valid_host_name(const char *name) @@ -386,7 +386,7 @@ cleanup: bool util_valid_time_tz(const char *time) { - char *patten = "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{2,9})?Z$"; + char *patten = "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{2,9})?(Z|[+-][0-9]{2}:[0-9]{2})$"; if (time == NULL) { ERROR("invalid NULL param"); diff --git a/src/http/CMakeLists.txt b/src/http/CMakeLists.txt index d495956..7f43258 100644 --- a/src/http/CMakeLists.txt +++ b/src/http/CMakeLists.txt @@ -16,7 +16,7 @@ target_include_directories(libhttpclient PUBLIC # set libhttpclient FLAGS set_target_properties(libhttpclient PROPERTIES PREFIX "") -target_link_libraries(libhttpclient ${HTTP_PARSER_LIBRARY} ${CURL_LIBRARY} ${LIBSECUREC_LIBRARY}) +target_link_libraries(libhttpclient ${HTTP_PARSER_LIBRARY} ${CURL_LIBRARY}) if (ISULAD_GCOV) target_link_libraries(libhttpclient -lgcov) diff --git a/src/http/rest_common.c b/src/http/rest_common.c index f195ecc..ba2d441 100644 --- a/src/http/rest_common.c +++ b/src/http/rest_common.c @@ -52,15 +52,15 @@ static int g_ops_status = 0; /* check status code */ int check_status_code(int status_code) { - if (status_code == EVHTP_RES_OK || status_code == EVHTP_RES_SERVERR) { + if (status_code == RESTFUL_RES_OK || status_code == RESTFUL_RES_SERVERR) { return 0; - } else if (status_code == EVHTP_RES_NOTIMPL) { + } else if (status_code == RESTFUL_RES_NOTIMPL) { ERROR("Not implement interface"); return -1; - } else if (status_code == EVHTP_RES_NOTFOUND) { + } else if (status_code == RESTFUL_RES_NOTFOUND) { ERROR("Can not connect to service"); return -1; - } else if (status_code == EVHTP_RES_ERROR) { + } else if (status_code == RESTFUL_RES_ERROR) { ERROR("Server internal error"); return -1; } diff --git a/src/http/rest_common.h b/src/http/rest_common.h index 7a369c0..e969ece 100644 --- a/src/http/rest_common.h +++ b/src/http/rest_common.h @@ -15,8 +15,6 @@ #ifndef __REST_COMMON_H #define __REST_COMMON_H -#include - #include "http/buffer.h" #include "http/http.h" #include "parser.h" @@ -25,6 +23,13 @@ extern "C" { #endif +// Response status from restful server +#define RESTFUL_RES_ERROR 0 +#define RESTFUL_RES_OK 200 +#define RESTFUL_RES_NOTFOUND 404 +#define RESTFUL_RES_SERVERR 500 +#define RESTFUL_RES_NOTIMPL 501 + typedef int (*unpack_response_func_t)(const struct parsed_http_message *message, void *arg); int get_response(Buffer *output, unpack_response_func_t unpack_func, void *arg); diff --git a/src/image/embedded/lim.c b/src/image/embedded/lim.c index d93aa2f..cdafe32 100644 --- a/src/image/embedded/lim.c +++ b/src/image/embedded/lim.c @@ -382,12 +382,6 @@ static bool validate_create_time(char *created) return false; } - /* ensure time can be processed by us */ - if (time_tz_to_seconds_nanos(created, NULL, NULL)) { - ERROR("invalid created time %s, invalid time value", created); - isulad_try_set_error_message("Invalid content in manifest: invalid created time"); - return false; - } return true; } diff --git a/src/image/image.c b/src/image/image.c index e3e8fcc..c9e5b30 100644 --- a/src/image/image.c +++ b/src/image/image.c @@ -28,6 +28,7 @@ #include "ext_image.h" #include "filters.h" +#include "collector.h" #ifdef ENABLE_OCI_IMAGE #include "isula_image.h" @@ -163,6 +164,10 @@ static const struct bim_type *bim_query(const char *image_name) WARN("Unimplements resolve image name in %s", g_bims[i].image_type); continue; } + if (g_bims[i].ops->detect == NULL) { + WARN("Unimplements detect in %s", g_bims[i].image_type); + continue; + } temp = g_bims[i].ops->resolve_image_name(image_name); if (temp == NULL) { isulad_append_error_message("Failed to resovle image name%s", image_name); @@ -236,6 +241,12 @@ static struct bim *bim_get(const char *image_type, const char *image_name, const bim->ops = q->ops; bim->type = q->image_type; + if (bim->ops->resolve_image_name == NULL) { + ERROR("Unimplements resolve image name"); + bim_put(bim); + return NULL; + } + if (image_name != NULL) { bim->image_name = bim->ops->resolve_image_name(image_name); if (bim->image_name == NULL) { @@ -919,6 +930,7 @@ int im_pull_image(const im_pull_request *request, im_pull_response **response) goto out; } EVENT("Event: {Object: %s, Type: Pulled}", request->image); + (void)isulad_monitor_send_image_event(request->image, IM_PULL); out: bim_put(bim); @@ -1049,13 +1061,40 @@ void free_im_load_response(im_load_response *ptr) free(ptr); } +static bool check_login_request(const im_login_request *request) +{ + if (request == NULL) { + ERROR("Invalid input arguments"); + return false; + } + + if (request->server == NULL) { + ERROR("Login requires server address"); + isulad_set_error_message("Login requires server address"); + return false; + } + + if (request->type == NULL) { + ERROR("Login requires image type"); + isulad_set_error_message("Login requires image type"); + return false; + } + + if (request->username == NULL || request->password == NULL) { + ERROR("Missing username or password"); + isulad_set_error_message("Missing username or password"); + return false; + } + return true; +} + int im_login(const im_login_request *request, im_login_response **response) { int ret = -1; struct bim *bim = NULL; - if (request == NULL || response == NULL) { - ERROR("Invalid input arguments"); + if (response == NULL) { + ERROR("Empty response"); return -1; } @@ -1065,21 +1104,7 @@ int im_login(const im_login_request *request, im_login_response **response) return -1; } - if (request->server == NULL) { - ERROR("Login requires server address"); - isulad_set_error_message("Login requires server address"); - goto pack_response; - } - - if (request->type == NULL) { - ERROR("Login requires image type"); - isulad_set_error_message("Login requires image type"); - goto pack_response; - } - - if (request->username == NULL || request->password == NULL) { - ERROR("Missing username or password"); - isulad_set_error_message("Missing username or password"); + if (!check_login_request(request)) { goto pack_response; } @@ -1089,6 +1114,11 @@ int im_login(const im_login_request *request, im_login_response **response) goto pack_response; } + if (bim->ops->login == NULL) { + ERROR("Unimplements login in %s", bim->type); + goto pack_response; + } + EVENT("Event: {Object: %s, Type: logining}", request->server); ret = bim->ops->login(request); @@ -1142,13 +1172,34 @@ void free_im_login_response(im_login_response *ptr) free(ptr); } +static bool check_logout_request(const im_logout_request *request) +{ + if (request == NULL) { + ERROR("Invalid input arguments"); + return false; + } + + if (request->server == NULL) { + ERROR("Logout requires server address"); + isulad_set_error_message("Logout requires server address"); + return false; + } + + if (request->type == NULL) { + ERROR("Logout requires image type"); + isulad_set_error_message("Logout requires image type"); + return false; + } + return true; +} + int im_logout(const im_logout_request *request, im_logout_response **response) { int ret = -1; struct bim *bim = NULL; - if (request == NULL || response == NULL) { - ERROR("Invalid input arguments"); + if (response == NULL) { + ERROR("Empty response"); return -1; } @@ -1158,15 +1209,7 @@ int im_logout(const im_logout_request *request, im_logout_response **response) return -1; } - if (request->server == NULL) { - ERROR("Logout requires server address"); - isulad_set_error_message("Logout requires server address"); - goto pack_response; - } - - if (request->type == NULL) { - ERROR("Logout requires image type"); - isulad_set_error_message("Logout requires image type"); + if (!check_logout_request(request)) { goto pack_response; } @@ -1176,6 +1219,11 @@ int im_logout(const im_logout_request *request, im_logout_response **response) goto pack_response; } + if (bim->ops->logout == NULL) { + ERROR("Unimplements logout in %s", bim->type); + goto pack_response; + } + EVENT("Event: {Object: %s, Type: logouting}", request->server); ret = bim->ops->logout(request); @@ -1335,6 +1383,7 @@ int im_rm_image(const im_remove_request *request, im_remove_response **response) } EVENT("Event: {Object: %s, Type: image removed}", image_ref); + (void)isulad_monitor_send_image_event(image_ref, IM_REMOVE); pack_response: if (g_isulad_errmsg != NULL) { @@ -1616,6 +1665,10 @@ static int bims_init(const struct im_configs *conf) size_t i; for (i = 0; i < g_numbims; i++) { + if (g_bims[i].ops->init == NULL) { + WARN("Unimplements init in %s", g_bims[i].image_type); + continue; + } ret = g_bims[i].ops->init(conf); if (ret != 0) { ERROR("Failed to init bim %s", g_bims[i].image_type); @@ -1759,4 +1812,3 @@ void im_sync_containers_isuladkit(void) } #endif } - diff --git a/src/image/image.h b/src/image/image.h index 8b72368..1a3d02f 100644 --- a/src/image/image.h +++ b/src/image/image.h @@ -382,4 +382,3 @@ void im_sync_containers_isuladkit(void); #endif #endif - diff --git a/src/image/oci/isula_image_fs_info.c b/src/image/oci/isula_image_fs_info.c index 6710433..df2754a 100644 --- a/src/image/oci/isula_image_fs_info.c +++ b/src/image/oci/isula_image_fs_info.c @@ -107,7 +107,7 @@ int isula_image_fs_info(im_fs_info_response *resp) struct isula_image_fs_info_request ireq = {0}; struct isula_image_fs_info_response *iresp = NULL; client_connect_config_t conf = { 0 }; - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; if (resp == NULL) { ERROR("Invalid arguments"); diff --git a/src/image/oci/isula_image_pull.c b/src/image/oci/isula_image_pull.c index bdf50e0..23184d5 100644 --- a/src/image/oci/isula_image_pull.c +++ b/src/image/oci/isula_image_pull.c @@ -103,7 +103,7 @@ static int isula_pull_response_to_im(const struct isula_pull_response *iresp, im int isula_pull_image(const im_pull_request *request, im_pull_response **response) { - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; struct isula_pull_request *ireq = NULL; struct isula_pull_response *iresp = NULL; int ret = -1; diff --git a/src/image/oci/isula_image_rmi.c b/src/image/oci/isula_image_rmi.c index c981a85..a6b9b11 100644 --- a/src/image/oci/isula_image_rmi.c +++ b/src/image/oci/isula_image_rmi.c @@ -56,7 +56,7 @@ int isula_image_rmi(const char *image, bool force, char **errmsg) struct isula_rmi_request *ireq = NULL; struct isula_rmi_response *iresp = NULL; client_connect_config_t conf = { 0 }; - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; im_ops = get_isula_image_ops(); if (im_ops == NULL) { diff --git a/src/image/oci/isula_image_status.c b/src/image/oci/isula_image_status.c index 7e43189..d237c5f 100644 --- a/src/image/oci/isula_image_status.c +++ b/src/image/oci/isula_image_status.c @@ -111,7 +111,7 @@ imagetool_image *isula_image_get_image_info_by_name(const char *image_name) struct isula_status_request *ireq = NULL; struct isula_status_response *iresp = NULL; client_connect_config_t conf = { 0 }; - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; imagetool_image *result = NULL; int ret = -1; diff --git a/src/image/oci/isula_images_list.c b/src/image/oci/isula_images_list.c index b9cf8b0..10f656f 100644 --- a/src/image/oci/isula_images_list.c +++ b/src/image/oci/isula_images_list.c @@ -147,7 +147,7 @@ int isula_list_images(const im_list_request *request, imagetool_images_list **im struct isula_list_request *ireq = NULL; struct isula_list_response *iresp = NULL; client_connect_config_t conf = { 0 }; - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; int ret = -1; im_ops = get_isula_image_ops(); diff --git a/src/image/oci/isula_login.c b/src/image/oci/isula_login.c index 89d9328..6617b0a 100644 --- a/src/image/oci/isula_login.c +++ b/src/image/oci/isula_login.c @@ -61,7 +61,7 @@ int isula_do_login(const char *server, const char *username, const char *passwor struct isula_login_request *ireq = NULL; struct isula_login_response *iresp = NULL; client_connect_config_t conf = { 0 }; - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; if (is_valid_arguments(server, username, password) != 0) { ERROR("Invalid arguments"); diff --git a/src/image/oci/isula_rootfs_mount.c b/src/image/oci/isula_rootfs_mount.c index a12707e..1beea06 100644 --- a/src/image/oci/isula_rootfs_mount.c +++ b/src/image/oci/isula_rootfs_mount.c @@ -45,7 +45,7 @@ int isula_rootfs_mount(const char *name_id) struct isula_mount_request *ireq = NULL; struct isula_mount_response *iresp = NULL; client_connect_config_t conf = { 0 }; - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; im_ops = get_isula_image_ops(); if (im_ops == NULL) { diff --git a/src/image/oci/isula_rootfs_remove.c b/src/image/oci/isula_rootfs_remove.c index 9b35962..04c0545 100644 --- a/src/image/oci/isula_rootfs_remove.c +++ b/src/image/oci/isula_rootfs_remove.c @@ -47,7 +47,7 @@ int isula_rootfs_remove(const char *name_id) struct isula_remove_request *ireq = NULL; struct isula_remove_response *iresp = NULL; client_connect_config_t conf = { 0 }; - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; im_ops = get_isula_image_ops(); if (im_ops == NULL) { diff --git a/src/image/oci/isula_rootfs_umount.c b/src/image/oci/isula_rootfs_umount.c index cca8e63..2cf4d5d 100644 --- a/src/image/oci/isula_rootfs_umount.c +++ b/src/image/oci/isula_rootfs_umount.c @@ -41,6 +41,21 @@ static int generate_isula_umount_request(const char *name_id, bool force, struct return 0; } +static bool is_container_nonexist_error(const struct isula_umount_response *iresp) +{ +#define CONTAINER_NOT_KNOWN_ERR "container not known" + if (iresp == NULL || iresp->errmsg == NULL) { + return false; + } + + if (strstr(iresp->errmsg, CONTAINER_NOT_KNOWN_ERR) != NULL) { + DEBUG("Container may already removed"); + return true; + } + + return false; +} + int isula_rootfs_umount(const char *name_id, bool force) { int ret = 0; @@ -48,7 +63,7 @@ int isula_rootfs_umount(const char *name_id, bool force) struct isula_umount_request *ireq = NULL; struct isula_umount_response *iresp = NULL; client_connect_config_t conf = { 0 }; - isula_image_ops *im_ops; + isula_image_ops *im_ops = NULL; im_ops = get_isula_image_ops(); if (im_ops == NULL) { @@ -81,7 +96,7 @@ int isula_rootfs_umount(const char *name_id, bool force) INFO("Send umount rootfs GRPC request"); nret = im_ops->umount(ireq, iresp, &conf); - if (nret != 0) { + if (nret != 0 && !is_container_nonexist_error(iresp)) { ERROR("Remove rootfs %s failed: %s", name_id, iresp != NULL ? iresp->errmsg : "null"); ret = -1; } diff --git a/src/image/oci/oci_config_merge.c b/src/image/oci/oci_config_merge.c index f925fee..8c8c4a5 100644 --- a/src/image/oci/oci_config_merge.c +++ b/src/image/oci/oci_config_merge.c @@ -97,8 +97,6 @@ static int oci_image_merge_env(const oci_image_spec_config *config, container_co } out: return ret; - - return 0; } static int do_duplicate_commands(const oci_image_spec_config *config, container_config *container_spec) @@ -172,6 +170,44 @@ static int oci_image_merge_entrypoint(const oci_image_spec_config *config, conta return 0; } +static int make_sure_container_config_labels(container_config *container_spec) +{ + if (container_spec->labels != NULL) { + return 0; + } + + container_spec->labels = util_common_calloc_s(sizeof(json_map_string_string)); + if (container_spec->labels == NULL) { + ERROR("Out of memory"); + return -1; + } + + return 0; +} + +static int oci_image_merge_labels(const oci_image_spec_config *config, container_config *container_spec) +{ + size_t i; + + if (config->labels == NULL || config->labels->len == 0) { + return 0; + } + + if (make_sure_container_config_labels(container_spec) != 0) { + return -1; + } + + for (i = 0; i < config->labels->len; i++) { + int ret = append_json_map_string_string(container_spec->labels, + config->labels->keys[i], config->labels->values[i]); + if (ret < 0) { + return -1; + } + } + + return 0; +} + static void oci_image_merge_user(const char *user, container_config *container_spec) { if (container_spec->user != NULL) { @@ -314,6 +350,11 @@ int oci_image_merge_config(imagetool_image *image_conf, container_config *contai oci_image_merge_user(image_conf->spec->config->user, container_spec); + if (oci_image_merge_labels(image_conf->spec->config, container_spec) != 0) { + ret = -1; + goto out; + } + // ignore volumes now } diff --git a/src/json/oci_runtime_hooks.h b/src/json/oci_runtime_hooks.h index dac9925..f31054a 100644 --- a/src/json/oci_runtime_hooks.h +++ b/src/json/oci_runtime_hooks.h @@ -18,8 +18,16 @@ # include "oci_runtime_spec.h" +#ifdef __cplusplus +extern "C" { +#endif + oci_runtime_spec_hooks *oci_runtime_spec_hooks_parse_file(const char *filename, const struct parser_context *ctx, parser_error *err); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/json/schema/schema/container/config-v2.json b/src/json/schema/schema/container/config-v2.json index 173886b..ba97bd8 100644 --- a/src/json/schema/schema/container/config-v2.json +++ b/src/json/schema/schema/container/config-v2.json @@ -40,6 +40,9 @@ "ResolvConfPath": { "type": "string" }, + "ShmPath": { + "type": "string" + }, "LogPath": { "type": "string" }, @@ -91,6 +94,18 @@ }, "id": { "type": "string" + }, + "MountLabel": { + "type": "string" + }, + "ProcessLabel": { + "type": "string" + }, + "SeccompProfile": { + "type": "string" + }, + "NoNewPrivileges": { + "type": "boolean" } }, "required": [ diff --git a/src/json/schema/schema/container/get-runtime-response.json b/src/json/schema/schema/container/get-runtime-response.json new file mode 100644 index 0000000..f767684 --- /dev/null +++ b/src/json/schema/schema/container/get-runtime-response.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "runtime": { + "type": "string" + }, + "cc": { + "type": "uint32" + }, + "errmsg": { + "type": "string" + } + } +} diff --git a/src/json/schema/schema/container/inspect.json b/src/json/schema/schema/container/inspect.json index 7d1573f..dc14e9f 100644 --- a/src/json/schema/schema/container/inspect.json +++ b/src/json/schema/schema/container/inspect.json @@ -75,6 +75,18 @@ "RestartCount":{ "type":"integer" }, + "MountLabel":{ + "type":"string" + }, + "ProcessLabel":{ + "type":"string" + }, + "SeccompProfile": { + "type": "string" + }, + "NoNewPrivileges": { + "type": "boolean" + }, "HostConfig":{ "$ref": "../host-config.json" }, diff --git a/src/json/schema/schema/defs.json b/src/json/schema/schema/defs.json index be56b15..c493a8a 100644 --- a/src/json/schema/schema/defs.json +++ b/src/json/schema/schema/defs.json @@ -232,6 +232,25 @@ } } }, + "mapStringObjectRuntimes": { + "type": "object", + "patternProperties": { + ".{1,}": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "runtime-args": { + "type":"array", + "items": { + "type":"string" + } + } + } + } + } + }, "ociVersion": { "description": "The version of Open Container Runtime Specification that the document complies with", "type": "string" diff --git a/src/json/schema/schema/host-config.json b/src/json/schema/schema/host-config.json index 9f8d44b..725c1e7 100644 --- a/src/json/schema/schema/host-config.json +++ b/src/json/schema/schema/host-config.json @@ -213,6 +213,9 @@ "MemorySwap": { "type": "int64" }, + "MemorySwappiness": { + "$ref": "defs.json#/definitions/uint64Pointer" + }, "OomKillDisable": { "type": "boolean" }, diff --git a/src/json/schema/schema/isulad-daemon-configs.json b/src/json/schema/schema/isulad-daemon-configs.json index eb289c0..e0293d4 100644 --- a/src/json/schema/schema/isulad-daemon-configs.json +++ b/src/json/schema/schema/isulad-daemon-configs.json @@ -5,6 +5,9 @@ "hosts": { "type": "ArrayOfStrings" }, + "default-runtime": { + "type": "string" + }, "group": { "type": "string" }, @@ -125,25 +128,31 @@ "type": "object", "patternProperties": { ".{1,}": { - "type": "object", - "required": [ - "Name", - "Hard", - "Soft" - ], - "properties": { - "Name": { - "type": "string" - }, - "Hard": { - "type": "int64" - }, - "Soft": { - "type": "int64" - } - } + "type": "object", + "required": [ + "Name", + "Hard", + "Soft" + ], + "properties": { + "Name": { + "type": "string" + }, + "Hard": { + "type": "int64" + }, + "Soft": { + "type": "int64" + } + } } } + }, + "runtimes": { + "$ref": "defs.json#/definitions/mapStringObjectRuntimes" + }, + "selinux-enabled" : { + "type": "boolean" } } } diff --git a/src/json/schema/schema/shim/client/process-state.json b/src/json/schema/schema/shim/client/process-state.json new file mode 100644 index 0000000..a80393d --- /dev/null +++ b/src/json/schema/schema/shim/client/process-state.json @@ -0,0 +1,193 @@ +{ + "description": "process state info", + "type": "object", + "required": [ + "cwd", + "args" + ], + "properties": { + "args": { + "id": "https://opencontainers.org/schema/bundle/process/args", + "$ref": "../../defs.json#/definitions/ArrayOfStrings" + }, + "consoleSize": { + "id": "https://opencontainers.org/schema/bundle/process/consoleSize", + "type": "object", + "required": [ + "height", + "width" + ], + "properties": { + "height": { + "id": "https://opencontainers.org/schema/bundle/process/consoleSize/height", + "$ref": "../../defs.json#/definitions/uint64" + }, + "width": { + "id": "https://opencontainers.org/schema/bundle/process/consoleSize/width", + "$ref": "../../defs.json#/definitions/uint64" + } + } + }, + "cwd": { + "id": "https://opencontainers.org/schema/bundle/process/cwd", + "type": "string" + }, + "env": { + "id": "https://opencontainers.org/schema/bundle/process/env", + "$ref": "../../defs.json#/definitions/Env" + }, + "terminal": { + "id": "https://opencontainers.org/schema/bundle/process/terminal", + "type": "boolean" + }, + "user": { + "id": "https://opencontainers.org/schema/bundle/process/user", + "type": "object", + "properties": { + "uid": { + "id": "https://opencontainers.org/schema/bundle/process/user/uid", + "$ref": "../../defs.json#/definitions/UID" + }, + "gid": { + "id": "https://opencontainers.org/schema/bundle/process/user/gid", + "$ref": "../../defs.json#/definitions/GID" + }, + "additionalGids": { + "id": "https://opencontainers.org/schema/bundle/process/user/additionalGids", + "$ref": "../../defs.json#/definitions/ArrayOfGIDs" + }, + "username": { + "id": "https://opencontainers.org/schema/bundle/process/user/username", + "type": "string" + } + } + }, + "capabilities": { + "id": "https://opencontainers.org/schema/bundle/process/linux/capabilities", + "type": "object", + "properties": { + "bounding": { + "id": "https://opencontainers.org/schema/bundle/process/linux/capabilities/bounding", + "type": "array", + "items": { + "type": "string" + } + }, + "permitted": { + "id": "https://opencontainers.org/schema/bundle/process/linux/capabilities/permitted", + "type": "array", + "items": { + "type": "string" + } + }, + "effective": { + "id": "https://opencontainers.org/schema/bundle/process/linux/capabilities/effective", + "type": "array", + "items": { + "type": "string" + } + }, + "inheritable": { + "id": "https://opencontainers.org/schema/bundle/process/linux/capabilities/inheritable", + "type": "array", + "items": { + "type": "string" + } + }, + "ambient": { + "id": "https://opencontainers.org/schema/bundle/process/linux/capabilities/ambient", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "apparmorProfile": { + "id": "https://opencontainers.org/schema/bundle/process/linux/apparmorProfile", + "type": "string" + }, + "oomScoreAdj": { + "id": "https://opencontainers.org/schema/bundle/process/linux/oomScoreAdj", + "type": "integer" + }, + "selinuxLabel": { + "id": "https://opencontainers.org/schema/bundle/process/linux/selinuxLabel", + "type": "string" + }, + "noNewPrivileges": { + "id": "https://opencontainers.org/schema/bundle/process/linux/noNewPrivileges", + "type": "boolean" + }, + "rlimits": { + "id": "https://opencontainers.org/schema/bundle/linux/rlimits", + "type": "array", + "items": { + "id": "https://opencontainers.org/schema/bundle/linux/rlimits/0", + "type": "object", + "required": [ + "type", + "soft", + "hard" + ], + "properties": { + "hard": { + "id": "https://opencontainers.org/schema/bundle/linux/rlimits/0/hard", + "$ref": "../../defs.json#/definitions/uint64" + }, + "soft": { + "id": "https://opencontainers.org/schema/bundle/linux/rlimits/0/soft", + "$ref": "../../defs.json#/definitions/uint64" + }, + "type": { + "id": "https://opencontainers.org/schema/bundle/linux/rlimits/0/type", + "type": "string", + "pattern": "^RLIMIT_[A-Z]+$" + } + } + } + }, + "exit_fifo": { + "type": "string" + }, + "control_fifo": { + "type": "string" + }, + "exec": { + "type": "boolean" + }, + "open_tty": { + "type": "boolean" + }, + "open_stdin": { + "type": "boolean" + }, + "isuladStdin": { + "type": "string" + }, + "isuladStdout": { + "type": "string" + }, + "isuladStderr": { + "type": "string" + }, + "runtimeArgs": { + "type": "array", + "items": { + "type": "string" + } + }, + "noPivotRoot": { + "tyoe": "boolean" + }, + "checkpoint": { + "type": "string" + }, + "rootUID": { + "type": "integer" + }, + "rootGID": { + "type": "integer" + } + } +} diff --git a/src/libisula.h b/src/libisula.h index 69633ac..d39a9e2 100644 --- a/src/libisula.h +++ b/src/libisula.h @@ -37,6 +37,9 @@ typedef struct isula_container_config { char **env; size_t env_len; + char **label; + size_t label_len; + char *hostname; char *user; diff --git a/src/libisulad.c b/src/libisulad.c index 2c35ef6..f35fd4f 100644 --- a/src/libisulad.c +++ b/src/libisulad.c @@ -14,13 +14,12 @@ ******************************************************************************/ #include #include +#include #include #include #include #include "libisulad.h" -#include "log.h" -#include "pack_config.h" #include "utils.h" // record the errno @@ -234,3 +233,26 @@ void container_log_config_free(struct container_log_config *conf) free(conf); } +void isulad_events_format_free(struct isulad_events_format *value) +{ + size_t i; + + if (value == NULL) { + return; + } + free(value->id); + value->id = NULL; + + free(value->opt); + value->opt = NULL; + + for (i = 0; i < value->annotations_len; i++) { + free(value->annotations[i]); + value->annotations[i] = NULL; + } + free(value->annotations); + value->annotations = NULL; + + free(value); +} + diff --git a/src/libisulad.h b/src/libisulad.h index 183166d..1f9e9ab 100644 --- a/src/libisulad.h +++ b/src/libisulad.h @@ -159,14 +159,17 @@ struct create_custom_config { }; struct isulad_events_format { - char *id; + types_timestamp_t timestamp; uint32_t has_type; container_events_type_t type; + char *opt; + char *id; + char **annotations; + size_t annotations_len; uint32_t has_pid; uint32_t pid; uint32_t has_exit_status; uint32_t exit_status; - types_timestamp_t timestamp; }; typedef void (handle_events_callback_t)(struct isulad_events_format *event); @@ -293,6 +296,7 @@ struct container_log_config { int rotate; int64_t size; }; + void container_log_config_free(struct container_log_config *conf); void isulad_events_request_free(struct isulad_events_request *request); @@ -317,6 +321,9 @@ void isulad_container_resize_response_free(struct isulad_container_resize_respon void isulad_logs_request_free(struct isulad_logs_request *request); void isulad_logs_response_free(struct isulad_logs_response *response); + +void isulad_events_format_free(struct isulad_events_format *value); + #ifdef __cplusplus } #endif diff --git a/src/namespace.c b/src/namespace.c index 9f13b63..9070cb2 100644 --- a/src/namespace.c +++ b/src/namespace.c @@ -21,7 +21,7 @@ #include "containers_store.h" -static char *connected_container(const char *mode) +char *connected_container(const char *mode) { const char *p = mode != NULL ? (mode + strlen(SHARE_NAMESPACE_PREFIX)) : NULL; @@ -97,3 +97,24 @@ char *get_share_namespace_path(const char *type, const char *src_path) return tmp_mode; } +char *get_container_process_label(const char *cid) +{ + char *result = NULL; + container_t *cont = NULL; + + if (cid == NULL) { + return NULL; + } + + cont = containers_store_get(cid); + if (cont == NULL) { + ERROR("Invalid share path: %s", cid); + goto out; + } + result = util_strdup_s(cont->common_config->process_label); + container_unref(cont); + +out: + return result; +} + diff --git a/src/namespace.h b/src/namespace.h index 7a7dc40..c90059d 100644 --- a/src/namespace.h +++ b/src/namespace.h @@ -18,9 +18,14 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define SHARE_NAMESPACE_PREFIX "container:" #define SHARE_NAMESPACE_HOST "host" #define SHARE_NAMESPACE_NONE "none" +#define SHARE_NAMESPACE_SHAREABLE "shareable" #define SHARE_NAMESPACE_PID_HOST_PATH "/proc/1/ns/pid" #define SHARE_NAMESPACE_NET_HOST_PATH "/proc/1/ns/net" @@ -68,7 +73,21 @@ static inline bool is_container(const char *mode) return false; } +static inline bool is_shareable(const char *mode) +{ + if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_SHAREABLE) == 0) { + return true; + } + return false; +} + +char *connected_container(const char *mode); char *get_share_namespace_path(const char *type, const char *src_path); +char *get_container_process_label(const char *path); + +#ifdef __cplusplus +} +#endif #endif diff --git a/src/pack_config.c b/src/pack_config.c index 90f3d7f..3b7bdef 100644 --- a/src/pack_config.c +++ b/src/pack_config.c @@ -647,6 +647,14 @@ static void pack_cgroup_resources_mem(host_config *dstconfig, const isula_host_c if (srcconfig->cr->kernel_memory) { dstconfig->kernel_memory = srcconfig->cr->kernel_memory; } + + // swappiness + if (srcconfig->cr->swappiness != -1) { + dstconfig->memory_swappiness = util_common_calloc_s(sizeof(uint64_t)); + if (dstconfig->memory_swappiness != NULL) { + *(dstconfig->memory_swappiness) = (uint64_t)(srcconfig->cr->swappiness); + } + } } static void pack_cgroup_resources(host_config *dstconfig, const isula_host_config_t *srcconfig) @@ -1162,76 +1170,83 @@ erro_out: free_host_config_host_channel(host_channel); return NULL; } +static int append_no_new_privileges_to_security_opts(host_config *dstconfig) +{ + int ret = 0; + size_t new_size, old_size; + char **tmp_security_opt = NULL; -static int parse_seccomp(const isula_host_config_t *srcconfig, host_config *dstconfig) + if (dstconfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) { + COMMAND_ERROR("Out of memory"); + return -1; + } + new_size = (dstconfig->security_opt_len + 1) * sizeof(char *); + old_size = dstconfig->security_opt_len * sizeof(char *); + ret = mem_realloc((void **)(&tmp_security_opt), new_size, (void *)dstconfig->security_opt, old_size); + if (ret != 0) { + COMMAND_ERROR("Out of memory"); + return ret; + } + dstconfig->security_opt = tmp_security_opt; + dstconfig->security_opt[dstconfig->security_opt_len++] = util_strdup_s("no-new-privileges"); + + return ret; +} + +static int append_seccomp_to_security_opts(const char *full_opt, const char *seccomp_file, host_config *dstconfig) { int ret = 0; int nret = 0; - int seccomp_count = 0; - size_t i = 0; size_t size = 0; - char *seccomp_file = NULL; char *seccomp_json = NULL; char *tmp_str = NULL; docker_seccomp *seccomp_spec = NULL; parser_error err = NULL; struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; - for (i = 0; i < srcconfig->security_len; i++) { - // add seccomp - if (strncmp(srcconfig->security[i], "seccomp=", strlen("seccomp=")) == 0) { - seccomp_file = srcconfig->security[i] + strlen("seccomp") + 1; - if (strcmp(seccomp_file, "unconfined") == 0) { - dstconfig->security_opt[seccomp_count++] = util_strdup_s(srcconfig->security[i]); - dstconfig->security_opt_len++; - continue; - } - seccomp_spec = get_seccomp_security_opt_spec(seccomp_file); - if (seccomp_spec == NULL) { - ERROR("Failed to parse docker format seccomp specification file \"%s\", error message: %s", - seccomp_file, err); - COMMAND_ERROR("failed to parse seccomp file: %s", seccomp_file); - ret = -1; - goto out; - } - - seccomp_json = docker_seccomp_generate_json(seccomp_spec, &ctx, &err); - if (seccomp_json == NULL) { - COMMAND_ERROR("failed to generate seccomp json!"); - ret = -1; - goto out; - } - - free_docker_seccomp(seccomp_spec); - seccomp_spec = NULL; - if (strlen(seccomp_json) > (SIZE_MAX - strlen("seccomp=")) - 1) { - COMMAND_ERROR("seccomp json is too big!"); - ret = -1; - goto out; - } - size = strlen("seccomp=") + strlen(seccomp_json) + 1; - tmp_str = util_common_calloc_s(size); - if (tmp_str == NULL) { - COMMAND_ERROR("out of memory"); - ret = -1; - goto out; - } - nret = snprintf(tmp_str, size, "seccomp=%s", seccomp_json); - if (nret < 0 || (size_t)nret >= size) { - COMMAND_ERROR("failed to sprintf buffer!"); - ret = -1; - goto out; - } - dstconfig->security_opt[seccomp_count++] = util_strdup_s(tmp_str); - dstconfig->security_opt_len++; - free(tmp_str); - tmp_str = NULL; - free(err); - err = NULL; - free(seccomp_json); - seccomp_json = NULL; - } + if (strcmp(seccomp_file, "unconfined") == 0) { + dstconfig->security_opt[dstconfig->security_opt_len] = util_strdup_s(full_opt); + dstconfig->security_opt_len++; + return 0; } + + seccomp_spec = get_seccomp_security_opt_spec(seccomp_file); + if (seccomp_spec == NULL) { + ERROR("Failed to parse docker format seccomp specification file \"%s\", error message: %s", + seccomp_file, err); + COMMAND_ERROR("failed to parse seccomp file: %s", seccomp_file); + ret = -1; + goto out; + } + + seccomp_json = docker_seccomp_generate_json(seccomp_spec, &ctx, &err); + if (seccomp_json == NULL) { + COMMAND_ERROR("failed to generate seccomp json!"); + ret = -1; + goto out; + } + + if (strlen(seccomp_json) > (SIZE_MAX - strlen("seccomp=")) - 1) { + COMMAND_ERROR("seccomp json is too big!"); + ret = -1; + goto out; + } + size = strlen("seccomp=") + strlen(seccomp_json) + 1; + tmp_str = util_common_calloc_s(size); + if (tmp_str == NULL) { + COMMAND_ERROR("out of memory"); + ret = -1; + goto out; + } + nret = snprintf(tmp_str, size, "seccomp=%s", seccomp_json); + if (nret < 0 || nret >= size) { + COMMAND_ERROR("failed to sprintf buffer!"); + ret = -1; + goto out; + } + dstconfig->security_opt[dstconfig->security_opt_len] = util_strdup_s(tmp_str); + dstconfig->security_opt_len++; + out: free(seccomp_json); free(tmp_str); @@ -1241,34 +1256,66 @@ out: return ret; } -static int parse_no_new_privileges(const isula_host_config_t *srcconfig, host_config *dstconfig) +static int append_selinux_label_to_security_opts(const char *selinux_label, host_config *dstconfig) { int ret = 0; - size_t i = 0; size_t new_size; size_t old_size; char **tmp_security_opt = NULL; + if (dstconfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) { + COMMAND_ERROR("Too large security options"); + return -1; + } + new_size = (dstconfig->security_opt_len + 1) * sizeof(char *); + old_size = dstconfig->security_opt_len * sizeof(char *); + ret = mem_realloc((void **)(&tmp_security_opt), new_size, (void *)dstconfig->security_opt, old_size); + if (ret != 0) { + COMMAND_ERROR("Out of memory"); + return ret; + } + dstconfig->security_opt = tmp_security_opt; + dstconfig->security_opt[dstconfig->security_opt_len++] = util_strdup_s(selinux_label); + + return ret; +} + +static int parse_security_opts(const isula_host_config_t *srcconfig, host_config *dstconfig) +{ + int ret = 0; + size_t i; + char **items = NULL; + for (i = 0; i < srcconfig->security_len; i++) { - // no new privileges - if (strcmp(srcconfig->security[i], "no-new-privileges") == 0) { - if (dstconfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) { - COMMAND_ERROR("Out of memory"); - return -1; + items = util_string_split_n(srcconfig->security[i], '=', 2); + if (util_array_len((const char **)items) == 1) { + if (strcmp(items[0], "no-new-privileges") != 0) { + ret = -1; + } else { + ret = append_no_new_privileges_to_security_opts(dstconfig); } - new_size = (dstconfig->security_opt_len + 1) * sizeof(char *); - old_size = dstconfig->security_opt_len * sizeof(char *); - ret = mem_realloc((void **)(&tmp_security_opt), new_size, (void *)dstconfig->security_opt, old_size); - if (ret != 0) { - COMMAND_ERROR("Out of memory"); - return ret; + } else { + if (strcmp(items[0], "seccomp") == 0) { + ret = append_seccomp_to_security_opts(srcconfig->security[i], items[1], dstconfig); + } else if (strcmp(items[0], "label") == 0) { + ret = append_selinux_label_to_security_opts(srcconfig->security[i], dstconfig); + } else { + ret = -1; } - dstconfig->security_opt = tmp_security_opt; - dstconfig->security_opt[dstconfig->security_opt_len++] = util_strdup_s(srcconfig->security[i]); - break; } + + if (ret != 0) { + COMMAND_ERROR("Invalid --security-opt: %s", srcconfig->security[i]); + ret = -1; + goto out; + } + + util_free_array(items); + items = NULL; } +out: + util_free_array(items); return ret; } @@ -1615,13 +1662,8 @@ int generate_security(host_config **dstconfig, const isula_host_config_t *srccon goto out; } - ret = parse_seccomp(srcconfig, (*dstconfig)); - if (ret < 0) { - goto out; - } - - ret = parse_no_new_privileges(srcconfig, (*dstconfig)); - if (ret < 0) { + if (parse_security_opts(srcconfig, (*dstconfig)) != 0) { + ret = -1; goto out; } @@ -1894,6 +1936,72 @@ out: return ret; } +static int get_label_key_value(const char *label, char **key, char **value) +{ + int ret = 0; + char **arr = util_string_split_n(label, '=', 2); + if (arr == NULL) { + ERROR("Failed to split input label"); + ret = -1; + goto out; + } + + *key = util_strdup_s(arr[0]); + if (util_array_len((const char **)arr) == 1) { + *value = util_strdup_s(""); + } else { + *value = util_strdup_s(arr[1]); + } + +out: + util_free_array(arr); + return ret; +} + +static int pack_container_custom_config_labels(container_config *container_spec, + const isula_container_config_t *custom_conf) +{ + int ret = 0; + int i; + char *key = NULL; + char *value = NULL; + + if (custom_conf->label_len == 0 || custom_conf->label == NULL) { + return 0; + } + + /* labels */ + container_spec->labels = util_common_calloc_s(sizeof(json_map_string_string)); + if (container_spec->labels == NULL) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + + for (i = 0; i < custom_conf->label_len; i++) { + if (get_label_key_value(custom_conf->label[i], &key, &value) != 0) { + ERROR("Failed to get key and value of label"); + ret = -1; + goto out; + } + + if (append_json_map_string_string(container_spec->labels, key, value)) { + ERROR("Append map failed"); + ret = -1; + goto out; + } + free(key); + key = NULL; + free(value); + value = NULL; + } + +out: + free(key); + free(value); + return ret; +} + static bool have_health_check(const isula_container_config_t *custom_conf) { bool have_health_settings = false; @@ -2053,6 +2161,11 @@ static int pack_container_custom_config_pre(container_config *container_spec, goto out; } + ret = pack_container_custom_config_labels(container_spec, custom_conf); + if (ret != 0) { + goto out; + } + ret = pack_container_custom_config_health(container_spec, custom_conf); if (ret != 0) { goto out; diff --git a/src/runtime/CMakeLists.txt b/src/runtime/CMakeLists.txt index 1a46eec..cdff938 100644 --- a/src/runtime/CMakeLists.txt +++ b/src/runtime/CMakeLists.txt @@ -2,15 +2,18 @@ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} runtime_top_srcs) add_subdirectory(lcr) +add_subdirectory(isula) set(local_runtime_srcs ${runtime_top_srcs} ${LCR_SRCS} + ${ISULA_SRCS} ) set(local_runtime_incs ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lcr + ${CMAKE_CURRENT_SOURCE_DIR}/isula ) set(RUNTIME_SRCS diff --git a/src/runtime/isula/CMakeLists.txt b/src/runtime/isula/CMakeLists.txt new file mode 100644 index 0000000..021875d --- /dev/null +++ b/src/runtime/isula/CMakeLists.txt @@ -0,0 +1,7 @@ +# get current directory sources files +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} local_isula_srcs) + +set(ISULA_SRCS + ${local_isula_srcs} + PARENT_SCOPE + ) diff --git a/src/runtime/isula/isula_rt_ops.c b/src/runtime/isula/isula_rt_ops.c new file mode 100644 index 0000000..16f78a5 --- /dev/null +++ b/src/runtime/isula/isula_rt_ops.c @@ -0,0 +1,1088 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jingrui + * Create: 2020-1-20 + * Description: runtime ops + ******************************************************************************/ + +#define _GNU_SOURCE + +#include +#include + +#include +#include "isula_rt_ops.h" +#include "log.h" +#include "error.h" +#include "runtime.h" +#include "engine.h" +#include "constants.h" +#include "shim_client_process_state.h" +#include "oci_runtime_state.h" +#include "isulad_config.h" + +#define SHIM_BINARY "isulad-shim" +#define SHIM_LOG_SIZE ((BUFSIZ-100)/2) +#define PID_WAIT_TIME 120 + +static void copy_process(shim_client_process_state *p, defs_process *dp) +{ + p->args = dp->args; + p->args_len = dp->args_len; + p->console_size = (shim_client_process_state_console_size *)dp->console_size; + p->cwd = dp->cwd; + p->env = dp->env; + p->env_len = dp->env_len; + p->terminal = dp->terminal; + p->user = (shim_client_process_state_user *)dp->user; + p->capabilities = (shim_client_process_state_capabilities *)dp->capabilities; + p->apparmor_profile = dp->apparmor_profile; + p->oom_score_adj = dp->oom_score_adj; + p->selinux_label = dp->selinux_label; + p->no_new_privileges = dp->no_new_privileges; + p->rlimits = (shim_client_process_state_rlimits_element **)dp->rlimits; + p->rlimits_len = dp->rlimits_len; +} + +static int file_write_int(const char *fname, int val) +{ + char sint[UINT_LEN] = {0}; + + if (snprintf(sint, sizeof(sint), "%d", val) < 0) { + return -1; + } + + if (util_write_file(fname, sint, strlen(sint), DEFAULT_SECURE_FILE_MODE) < 0) { + return -1; + } + + return 0; +} + +/* val will updated only when success. */ +static void file_read_int(const char *fname, int *val) +{ + char *sint = NULL; + int ival = 0; + + if (!util_file_exists(fname)) { + free(sint); + return; + } + + sint = util_read_text_file(fname); + if (sint == NULL) { + return; + } + + if (!util_safe_int(sint, &ival)) { + *val = ival; + } + + free(sint); +} + +static void get_err_message(char *buf, int buf_size, const char *workdir, const char *file) +{ + char fname[PATH_MAX] = {0}; + FILE *fp = NULL; + char *pline = NULL; + char *lines[3] = {0}; + size_t length = 0; + + if (snprintf(fname, sizeof(fname), "%s/%s", workdir, file) < 0) { + ERROR("failed make full path %s/%s", workdir, file); + return; + } + + fp = util_fopen(fname, "r"); + if (fp == NULL) { + return; + } + + while (getline(&pline, &length, fp) != -1) { + if (pline == NULL) { + break; + } + if (strings_contains_word(pline, "error")) { + if (lines[0] == NULL) { + lines[0] = pline; + pline = NULL; + continue; + } + if (lines[1] == NULL) { + lines[1] = pline; + pline = NULL; + continue; + } + if (lines[2] == NULL) { + lines[2] = pline; + pline = NULL; + break; + } + } + } + fclose(fp); + + if (lines[2] != NULL) { + (void)snprintf(buf, buf_size, "%s%s%s", lines[0], lines[1], lines[2]); + } else if (lines[1] != NULL) { + (void)snprintf(buf, buf_size, "%s%s", lines[0], lines[1]); + } else if (lines[0] != NULL) { + (void)snprintf(buf, buf_size, "%s", lines[0]); + } + + UTIL_FREE_AND_SET_NULL(pline); + UTIL_FREE_AND_SET_NULL(lines[0]); + UTIL_FREE_AND_SET_NULL(lines[1]); + UTIL_FREE_AND_SET_NULL(lines[2]); +} + +static void show_shim_runtime_errlog(const char *workdir) +{ + char buf[BUFSIZ] = {0}; + char buf1[SHIM_LOG_SIZE] = {0}; + char buf2[SHIM_LOG_SIZE] = {0}; + + get_err_message(buf1, sizeof(buf1), workdir, "shim-log.json"); + get_err_message(buf2, sizeof(buf2), workdir, "log.json"); + ERROR("shim-log: %s", buf1); + ERROR("runtime-log: %s", buf2); + (void)snprintf(buf, sizeof(buf), "shim-log error: %s\nruntime-log error: %s\n", buf1, buf2); + isulad_set_error_message(buf); +} + +bool rt_isula_detect(const char *runtime) +{ + if (runtime != NULL && (strcasecmp(runtime, "lcr") != 0)) { + return true; + } + + return false; +} + +static int create_process_json_file(const char *workdir, const shim_client_process_state *p) +{ + struct parser_context ctx = {OPT_GEN_SIMPLIFY, 0}; + parser_error perr = NULL; + char *data = NULL; + char fname[PATH_MAX] = {0}; + int retcode = 0; + + if (snprintf(fname, sizeof(fname), "%s/process.json", workdir) < 0) { + ERROR("failed make process.json full path"); + return -1; + } + + data = shim_client_process_state_generate_json(p, &ctx, &perr); + if (data == NULL) { + retcode = -1; + ERROR("failed generate json for process.json error=%s", perr); + goto out; + } + + if (util_write_file(fname, data, strlen(data), DEFAULT_SECURE_FILE_MODE) != 0) { + retcode = -1; + ERROR("failed write process.json"); + goto out; + } + +out: + UTIL_FREE_AND_SET_NULL(perr); + UTIL_FREE_AND_SET_NULL(data); + + return retcode; +} + +static void get_runtime_cmd(const char *runtime, const char **cmd) +{ + struct service_arguments *args = NULL; + defs_map_string_object_runtimes *runtimes = NULL; + size_t i = 0; + + if (isulad_server_conf_rdlock()) { + ERROR("failed to lock server config"); + goto out; + } + + args = conf_get_server_conf(); + if (args == NULL) { + ERROR("failed to get server config"); + goto unlock_out; + } + + if (args->json_confs != NULL) { + runtimes = args->json_confs->runtimes; + } + if (runtimes == NULL) { + goto unlock_out; + } + + for (i = 0; i < runtimes->len; i++) { + if (strcmp(runtime, runtimes->keys[i]) == 0) { + *cmd = runtimes->values[i]->path; + goto unlock_out; + } + } + +unlock_out: + if (isulad_server_conf_unlock()) { + ERROR("failed to unlock server config"); + } +out: + if (strcmp(runtime, "runc") == 0) { + *cmd = "runc"; + return; + } + + if (strcmp(runtime, "kata-runtime") == 0) { + *cmd = "kata-runtime"; + return; + } + if (*cmd == NULL) { + ERROR("missing match runtime config for %s", runtime); + } +} + +static int get_runtime_args(const char *runtime, const char ***args) +{ + int ret = 0; + struct service_arguments *gargs = NULL; + defs_map_string_object_runtimes *runtimes = NULL; + size_t i = 0; + + if (runtime == NULL) { + return 0; + } + + if (isulad_server_conf_rdlock()) { + ERROR("failed to lock server config"); + goto out; + } + + gargs = conf_get_server_conf(); + if (gargs == NULL) { + ERROR("failed to get server config"); + goto unlock_out; + } + + if (gargs->json_confs != NULL) { + runtimes = gargs->json_confs->runtimes; + } + if (runtimes == NULL) { + goto unlock_out; + } + + for (i = 0; i < runtimes->len; i++) { + if (strcmp(runtime, runtimes->keys[i]) == 0) { + *args = (const char **)runtimes->values[i]->runtime_args; + ret = runtimes->values[i]->runtime_args_len; + goto unlock_out; + } + } +unlock_out: + if (isulad_server_conf_unlock()) { + ERROR("failed to unlock server config"); + } +out: + return ret; +} + +static bool shim_alive(const char *workdir) +{ + int pid = 0; + char fpid[PATH_MAX] = {0}; + int ret = 0; + + if (snprintf(fpid, sizeof(fpid), "%s/shim-pid", workdir) < 0) { + ERROR("failed make shim-pid full path"); + return false; + } + + file_read_int(fpid, &pid); + + if (pid == 0) { + ERROR("failed read shim-pid file %s", fpid); + return false; + } + + ret = kill(pid, 0); + if (ret != 0) { + INFO("kill 0 shim-pid with error: %s", strerror(errno)); + } + return ret == 0; +} + +typedef struct { + const char *workdir; + const char *runtime; + const char *cmd; + const char **args; + size_t args_len; + const char *subcmd; + const char **opts; + size_t opts_len; + const char *id; + char **params; + size_t params_num; +} runtime_exec_info; + +static void runtime_exec_param_dump(const char **params) +{ + char *full = NULL; + int i = 0; + + for (i = 0; i < PARAM_NUM; i++) { + if (*(params + i) == NULL) { + full = util_string_join(" ", params, i); + INFO("runtime call params[%d] %s", i, full); + UTIL_FREE_AND_SET_NULL(full); + return; + } + } +} + +static void runtime_exec_param_init(runtime_exec_info *rei) +{ + const char **params = (const char **)rei->params; + size_t j = 0; + + *params++ = rei->cmd; + + for (j = 0; j < rei->args_len; j++) { + *params++ = *(rei->args + j); + } + + *params++ = rei->subcmd; + for (j = 0; j < rei->opts_len; j++) { + *params++ = *(rei->opts + j); + } + + if (rei->id) { + *params++ = rei->id; + } + if (strcmp(rei->subcmd, "kill") == 0) { + *params++ = "9"; + } +} + +static void runtime_exec_info_init(runtime_exec_info *rei, + const char *workdir, const char *runtime, + const char *subcmd, const char **opts, size_t opts_len, const char *id, + char **params, size_t params_num) +{ + rei->workdir = workdir; + rei->runtime = runtime; + rei->args_len = get_runtime_args(runtime, &rei->args); + get_runtime_cmd(runtime, &rei->cmd); + rei->subcmd = subcmd; + rei->opts = opts; + rei->opts_len = opts_len; + rei->id = id; + rei->params = params; + rei->params_num = params_num; + + runtime_exec_param_init(rei); + runtime_exec_param_dump((const char **)rei->params); +} + + +static void runtime_exec_func(void *arg) +{ + runtime_exec_info *rei = (runtime_exec_info *) arg; + + if (rei == NULL) { + dprintf(STDERR_FILENO, "missing runtime exec info"); + _exit(EXIT_FAILURE); + } + + if (chdir(rei->workdir) < 0) { + dprintf(STDERR_FILENO, "chdir %s failed", rei->workdir); + _exit(EXIT_FAILURE); + } + + execvp(rei->cmd, rei->params); + dprintf(STDERR_FILENO, "exec %s %s %s failed", rei->cmd, rei->subcmd, rei->id); + _exit(EXIT_FAILURE); +} + +static int status_string_to_int(const char *status) +{ + if (strcmp(status, "running") == 0) { + return ENGINE_CONTAINER_STATUS_RUNNING; + } + if (strcmp(status, "stopped") == 0) { + return ENGINE_CONTAINER_STATUS_STOPPED; + } + if (strcmp(status, "paused") == 0) { + return ENGINE_CONTAINER_STATUS_PAUSED; + } + return ENGINE_CONTAINER_STATUS_UNKNOWN; +} + +static int runtime_call_status(const char *workdir, const char *runtime, + const char *id, struct engine_container_status_info *ecsi) +{ + char *stdout = NULL; + char *stderr = NULL; + oci_runtime_state *state = NULL; + struct parser_context ctx = {OPT_GEN_SIMPLIFY, 0}; + parser_error perr = NULL; + runtime_exec_info rei = { 0 }; + int ret = 0; + char *params[PARAM_NUM] = {0}; + + runtime_exec_info_init(&rei, workdir, runtime, "state", NULL, 0, id, params, PARAM_NUM); + + if (!util_exec_cmd(runtime_exec_func, &rei, NULL, &stdout, &stderr)) { + ERROR("call runtime status failed: %s", stderr); + ret = -1; + goto out; + } + + if (stdout == NULL) { + ERROR("call runtime status no stdout"); + ret = -1; + goto out; + } + + state = oci_runtime_state_parse_data(stdout, &ctx, &perr); + if (state == NULL) { + ERROR("call runtime status parse json failed"); + ret = -1; + goto out; + } + + ecsi->status = status_string_to_int(state->status); + ecsi->pid = state->pid; + if (state->pid != 0) { + ecsi->has_pid = true; + } + + INFO("container %s status %s pid %d", id, state->status, state->pid); + +out: + free_oci_runtime_state(state); + UTIL_FREE_AND_SET_NULL(stdout); + UTIL_FREE_AND_SET_NULL(stderr); + UTIL_FREE_AND_SET_NULL(perr); + return ret; +} + +static int runtime_call_simple(const char *workdir, const char *runtime, + const char *subcmd, const char **opts, size_t opts_len, const char *id) +{ + runtime_exec_info rei = {0}; + char *stdout = NULL; + char *stderr = NULL; + int ret = 0; + char *params[PARAM_NUM] = {0}; + + runtime_exec_info_init(&rei, workdir, runtime, subcmd, opts, opts_len, id, params, PARAM_NUM); + if (!util_exec_cmd(runtime_exec_func, &rei, NULL, &stdout, &stderr)) { + WARN("call runtime %s failed stderr %s", subcmd, stderr); + goto out; + } + +out: + UTIL_FREE_AND_SET_NULL(stdout); + UTIL_FREE_AND_SET_NULL(stderr); + return ret; +} + +static int runtime_call_kill_force(const char *workdir, const char *runtime, const char *id) +{ + return runtime_call_simple(workdir, runtime, "kill", NULL, 0, id); +} + +static int runtime_call_delete_force(const char *workdir, const char *runtime, const char *id) +{ + const char *opts[1] = {"--force"}; + return runtime_call_simple(workdir, runtime, "delete", opts, 1, id); +} + +#define ExitSignalOffset 128 +static int status_to_exit_code(int status) +{ + int exit_code = 0; + + if (WIFEXITED(status)) { + exit_code = WEXITSTATUS(status); + } else { + exit_code = -1; + exit_code = -1; + } + if (WIFSIGNALED(status)) { + int signal; + signal = WTERMSIG(status); + exit_code = ExitSignalOffset + signal; + } + return exit_code; +} + +static int shim_create(bool fg, const char *id, const char *workdir, + const char *bundle, const char *runtime_cmd, + int *exit_code) +{ + pid_t pid = 0; + int exec_fd[2] = { -1, -1 }; + int num = 0; + int ret = 0; + char exec_buff[BUFSIZ + 1] = { 0 }; + char fpid[PATH_MAX] = {0}; + const char *params[PARAM_NUM] = {0}; + int i = 0; + int status = 0; + + params[i++] = SHIM_BINARY; + params[i++] = id; + params[i++] = bundle; + params[i++] = runtime_cmd; + params[i++] = "info"; + params[i++] = "2m0s"; + runtime_exec_param_dump(params); + + if (snprintf(fpid, sizeof(fpid), "%s/shim-pid", workdir) < 0) { + ERROR("failed make shim-pid full path"); + return -1; + } + + if (pipe2(exec_fd, O_CLOEXEC) != 0) { + ERROR("failed to create pipe for shim create"); + return -1; + } + + pid = fork(); + if (pid < 0) { + ERROR("failed fork for shim parent %s", strerror(errno)); + close(exec_fd[0]); + close(exec_fd[1]); + return -1; + } + + if (pid == (pid_t)0) { + if (chdir(workdir) < 0) { + (void)dprintf(exec_fd[1], "%s: failed chdir to %s", id, workdir); + exit(EXIT_FAILURE); + } + + if (fg) { + goto realexec; + } + + pid = fork(); + if (pid < 0) { + (void)dprintf(exec_fd[1], "%s: fork shim-process failed %s", id, strerror(errno)); + _exit(EXIT_FAILURE); + } + if (pid != 0) { + if (file_write_int(fpid, pid) != 0) { + (void)dprintf(exec_fd[1], "%s: write %s with %d failed", id, fpid, pid); + } + _exit(EXIT_SUCCESS); + } + +realexec: + /* real shim process. */ + close(exec_fd[0]); + if (setsid() < 0) { + (void)dprintf(exec_fd[1], "%s: failed setsid for process %d", id, getpid()); + exit(EXIT_FAILURE); + } + + if (util_check_inherited(true, exec_fd[1]) != 0) { + (void)dprintf(exec_fd[1], "close inherited fds failed"); + } + + execvp(SHIM_BINARY, (char * const *)params); + (void)dprintf(exec_fd[1], "exec failed: %s", strerror(errno)); + } + + close(exec_fd[1]); + num = util_read_nointr(exec_fd[0], exec_buff, sizeof(exec_buff)); + close(exec_fd[0]); + if (num > 0) { + ERROR("exec failed: %s", exec_buff); + ret = -1; + goto out; + } + + status = wait_for_pid_status(pid); + if (status < 0) { + ERROR("failed wait shim-parent %d exit %s", pid, strerror(errno)); + ret = -1; + goto out; + } + + if (exit_code != NULL) { + *exit_code = status_to_exit_code(status); + } + +out: + if (ret != 0) { + show_shim_runtime_errlog(workdir); + kill(pid, SIGKILL); /* can kill other process? */ + } + + return ret; +} + + +static int get_container_process_pid(const char *workdir) +{ + char fname[PATH_MAX] = {0}; + int pid = 0; + struct timespec beg = {0}; + struct timespec end = {0}; + + if (snprintf(fname, sizeof(fname), "%s/pid", workdir) < 0) { + ERROR("failed make pid full path"); + return -1; + } + + if (clock_gettime(CLOCK_MONOTONIC, &beg) != 0) { + ERROR("failed get time"); + return -1; + } + + while (1) { + if (clock_gettime(CLOCK_MONOTONIC, &end) != 0) { + ERROR("failed get time"); + return -1; + } + if (end.tv_sec - beg.tv_sec > PID_WAIT_TIME) { + ERROR("wait container process pid timeout %s", workdir); + return -1; + } + file_read_int(fname, &pid); + if (!pid) { + if (shim_alive(workdir)) { + usleep_nointerupt(100000); + continue; + } + ERROR("failed read pid from dead shim %s", workdir); + return -1; + } + return pid; /* success */ + } + return -1; +} + +static void shim_kill_force(const char *workdir) +{ + int pid = 0; + char fpid[PATH_MAX] = {0}; + + if (snprintf(fpid, sizeof(fpid), "%s/shim-pid", workdir) < 0) { + INFO("shim-pid not exist"); + return; + } + + file_read_int(fpid, &pid); + + if (pid == 0) { + goto out; + } + + kill(pid, SIGKILL); + +out: + INFO("kill shim force %s", workdir); +} + +int rt_isula_create(const char *id, const char *runtime, + const rt_create_params_t *params) +{ + oci_runtime_spec *config = NULL; + const char *cmd = NULL; + const char **runtime_args = NULL; + size_t runtime_args_len = 0; + int ret = 0; + char workdir[PATH_MAX] = {0}; + shim_client_process_state p = {0}; + + if (id == NULL || runtime == NULL || params == NULL) { + ERROR("nullptr arguments not allowed"); + return -1; + } + config = params->oci_config_data; + runtime_args_len = get_runtime_args(runtime, &runtime_args); + + if (snprintf(workdir, sizeof(workdir), "%s/%s", params->state, id) < 0) { + INFO("make full workdir failed"); + ret = -1; + goto out; + } + + p.exit_fifo = (char *)params->exit_fifo; + p.open_tty = params->tty; + p.open_stdin = params->open_stdin; + p.isulad_stdin = (char *)params->stdin; + p.isulad_stdout = (char *)params->stdout; + p.isulad_stderr = (char *)params->stderr; + p.runtime_args = (char **)runtime_args; + p.runtime_args_len = runtime_args_len; + copy_process(&p, config->process); + + ret = create_process_json_file(workdir, &p); + if (ret != 0) { + ERROR("%s: failed create json file", id); + goto out; + } + + get_runtime_cmd(runtime, &cmd); + ret = shim_create(false, id, workdir, params->bundle, cmd, NULL); + if (ret != 0) { + runtime_call_delete_force(workdir, runtime, id); + ERROR("%s: failed create shim process", id); + goto out; + } + +out: + return ret; +} + +int rt_isula_start(const char *id, const char *runtime, + const rt_start_params_t *params, + container_pid_t *pid_info) +{ + char workdir[PATH_MAX] = {0}; + pid_t pid = 0; + int ret = 0; + + if (id == NULL || runtime == NULL || params == NULL || pid_info == NULL) { + ERROR("nullptr arguments not allowed"); + return -1; + } + if (snprintf(workdir, sizeof(workdir), "%s/%s", params->state, id) < 0) { + ERROR("%s: missing shim workdir", id); + return -1; + } + + pid = get_container_process_pid(workdir); + if (pid < 0) { + ret = -1; + ERROR("%s: failed wait init pid", id); + goto out; + } + + if (container_read_proc(pid, pid_info) != 0) { + ret = -1; + ERROR("%s: failed read pid info", id); + goto out; + } + + if (runtime_call_simple(workdir, runtime, "start", NULL, 0, id) != 0) { + ERROR("call runtime start id failed"); + ret = -1; + goto out; + } + +out: + if (ret != 0) { + show_shim_runtime_errlog(workdir); + shim_kill_force(workdir); + } + + return ret; +} + +int rt_isula_restart(const char *name, const char *runtime, + const rt_restart_params_t *params) +{ + ERROR(">>> restart not implemented"); + return RUNTIME_NOT_IMPLEMENT_RESET; +} + +int rt_isula_clean_resource(const char *id, const char *runtime, + const rt_clean_params_t *params) +{ + char workdir[PATH_MAX] = {0}; + + if (id == NULL || runtime == NULL || params == NULL) { + ERROR("nullptr arguments not allowed"); + return -1; + } + + if (params->statepath == NULL) { + ERROR("missing state path"); + return -1; + } + + if (snprintf(workdir, sizeof(workdir), "%s/%s", params->statepath, id) < 0) { + ERROR("failed get shim workdir"); + return -1; + } + + if (shim_alive(workdir)) { + shim_kill_force(workdir); + } + + (void)runtime_call_kill_force(workdir, runtime, id); + (void)runtime_call_delete_force(workdir, runtime, id); + + if (util_recursive_rmdir(workdir, 0) != 0) { + ERROR("failed rmdir -r shim workdir"); + return -1; + } + + INFO("rmdir -r %s done", workdir); + return 0; +} + +int rt_isula_rm(const char *id, const char *runtime, const rt_rm_params_t *params) +{ + char libdir[PATH_MAX] = {0}; + + if (id == NULL || runtime == NULL || params == NULL) { + ERROR("nullptr arguments not allowed"); + return -1; + } + if (params->rootpath == NULL) { + ERROR("missing root path"); + return -1; + } + if (snprintf(libdir, sizeof(libdir), "%s/%s", params->rootpath, id) < 0) { + ERROR("failed get shim workdir"); + return -1; + } + + if (util_recursive_rmdir(libdir, 0) != 0) { + ERROR("failed rmdir -r shim workdir"); + return -1; + } + + INFO("rmdir -r %s done", libdir); + return 0; +} + +static char *try_generate_exec_id() +{ + char *id = NULL; + + id = util_common_calloc_s(sizeof(char) * (CONTAINER_EXEC_ID_MAX_LEN + 1)); + if (id == NULL) { + ERROR("Out of memory"); + return NULL; + } + + if (util_generate_random_str(id, (size_t)CONTAINER_EXEC_ID_MAX_LEN)) { + ERROR("Generate id failed"); + goto err_out; + } + + return id; + +err_out: + free(id); + return NULL; +} + +static bool fg_exec(const rt_exec_params_t *params) +{ + if (params->console_fifos[0] != NULL || params->console_fifos[1] != NULL || + params->console_fifos[2] != NULL) { + return true; + } + return false; +} + +int rt_isula_exec(const char *id, const char *runtime, + const rt_exec_params_t *params, int *exit_code) +{ + char *exec_id = NULL; + defs_process *process = NULL; + const char **runtime_args = NULL; + size_t runtime_args_len = 0; + char workdir[PATH_MAX] = {0}; + const char *cmd = NULL; + int ret = 0; + char bundle[PATH_MAX] = {0}; + int pid = 0; + shim_client_process_state p = {0}; + + if (id == NULL || runtime == NULL || params == NULL || exit_code == NULL) { + ERROR("nullptr arguments not allowed"); + return -1; + } + process = params->spec; + runtime_args_len = get_runtime_args(runtime, &runtime_args); + + ret = snprintf(bundle, sizeof(bundle), "%s/%s", params->rootpath, id); + if (ret < 0) { + ERROR("failed join bundle path for exec"); + goto out; + } + + exec_id = try_generate_exec_id(); + if (exec_id == NULL) { + ERROR("Failed to generate exec id"); + ret = -1; + goto out; + } + + ret = snprintf(workdir, sizeof(workdir), "%s/%s/exec/%s", params->state, id, exec_id); + if (ret < 0) { + ERROR("failed join exec full path"); + goto out; + } + ret = util_mkdir_p(workdir, DEFAULT_SECURE_DIRECTORY_MODE); + if (ret < 0) { + ERROR("failed mkdir exec workdir %s", workdir); + goto out; + } + + p.exec = true; + p.isulad_stdin = (char *)params->console_fifos[0]; + p.isulad_stdout = (char *)params->console_fifos[1]; + p.isulad_stderr = (char *)params->console_fifos[2]; + p.runtime_args = (char **)runtime_args; + p.runtime_args_len = runtime_args_len; + copy_process(&p, process); + + ret = create_process_json_file(workdir, &p); + if (ret != 0) { + ERROR("%s: failed create exec json file"); + goto out; + } + + get_runtime_cmd(runtime, &cmd); + ret = shim_create(fg_exec(params), id, workdir, bundle, cmd, exit_code); + if (ret != 0) { + ERROR("%s: failed create shim process for exec %s", id, exec_id); + goto out; + } + + pid = get_container_process_pid(workdir); + if (pid < 0) { + ERROR("%s: failed get exec process id", workdir); + ret = -1; + goto out; + } + +out: + UTIL_FREE_AND_SET_NULL(exec_id); + if (ret != 0) { + show_shim_runtime_errlog(workdir); + } else { + if (util_recursive_rmdir(workdir, 0)) { + ERROR("rmdir %s failed", workdir); + } + } + return ret; +} + +int rt_isula_status(const char *id, const char *runtime, + const rt_status_params_t *params, + struct engine_container_status_info *status) +{ + char workdir[PATH_MAX] = {0}; + int ret = 0; + + if (id == NULL || runtime == NULL || params == NULL || status == NULL) { + ERROR("nullptr arguments not allowed"); + return -1; + } + + ret = snprintf(workdir, sizeof(workdir), "%s/%s", params->state, id); + if (ret < 0) { + ERROR("failed join full workdir %s/%s", params->rootpath, id); + goto out; + } + + if (!shim_alive(workdir)) { + ERROR("shim dead %s", workdir); + ret = -1; + goto out; + } + + ret = runtime_call_status(workdir, runtime, id, status); + +out: + return ret; +} + +int rt_isula_attach(const char *id, const char *runtime, + const rt_attach_params_t *params) +{ + ERROR("isula attach not support on isulad-shim"); + isulad_set_error_message("isula attach not support on isulad-shim"); + return -1; +} + +int rt_isula_update(const char *id, const char *runtime, const rt_update_params_t *params) +{ + ERROR("isula update not support on isulad-shim"); + isulad_set_error_message("isula update not support on isulad-shim"); + return -1; +} + +int rt_isula_pause(const char *id, const char *runtime, const rt_pause_params_t *params) +{ + char workdir[PATH_MAX] = {0}; + + if (id == NULL || runtime == NULL || params == NULL) { + ERROR("nullptr arguments not allowed"); + return -1; + } + + if (snprintf(workdir, sizeof(workdir), "%s/%s", params->state, id) < 0) { + ERROR("failed join workdir %s/%s", params->state, id); + return -1; + } + + return runtime_call_simple(workdir, runtime, "pause", NULL, 0, id); +} + +int rt_isula_resume(const char *id, const char *runtime, const rt_resume_params_t *params) +{ + char workdir[PATH_MAX] = {0}; + + if (id == NULL || runtime == NULL || params == NULL) { + ERROR("nullptr arguments not allowed"); + return -1; + } + + if (snprintf(workdir, sizeof(workdir), "%s/%s", params->state, id) < 0) { + ERROR("failed join workdir %s/%s", params->state, id); + return -1; + } + + return runtime_call_simple(workdir, runtime, "resume", NULL, 0, id); +} + +int rt_isula_listpids(const char *name, const char *runtime, const rt_listpids_params_t *params, rt_listpids_out_t *out) +{ + ERROR("isula top/listpids not support on isulad-shim"); + isulad_set_error_message("isula top/listpids not support on isulad-shim"); + return -1; +} + +int rt_isula_resources_stats(const char *name, const char *runtime, + const rt_stats_params_t *params, + struct engine_container_resources_stats_info *rs_stats) +{ + ERROR("isula stats not support on isulad-shim"); + isulad_set_error_message("isula stats not support on isulad-shim"); + return -1; +} + +int rt_isula_resize(const char *id, const char *runtime, const rt_resize_params_t *params) +{ + ERROR("rt_isula_resize not impl"); + return 0; +} + +int rt_isula_exec_resize(const char *id, const char *runtime, const rt_exec_resize_params_t *params) +{ + ERROR("rt_isula_exec_resize not impl"); + return 0; +} diff --git a/src/runtime/isula/isula_rt_ops.h b/src/runtime/isula/isula_rt_ops.h new file mode 100644 index 0000000..5f46c04 --- /dev/null +++ b/src/runtime/isula/isula_rt_ops.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jingrui + * Create: 2020-1-20 + * Description: runtime ops + ******************************************************************************/ + +#ifndef ISULA_RT_OPS_H +#define ISULA_RT_OPS_H /* ISULA_RT_OPS_H */ + +#include "runtime.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool rt_isula_detect(const char *runtime); +int rt_isula_create(const char *name, const char *runtime, const rt_create_params_t *params); +int rt_isula_start(const char *name, const char *runtime, const rt_start_params_t *params, container_pid_t *pid_info); +int rt_isula_restart(const char *name, const char *runtime, const rt_restart_params_t *params); +int rt_isula_clean_resource(const char *name, const char *runtime, const rt_clean_params_t *params); +int rt_isula_rm(const char *name, const char *runtime, const rt_rm_params_t *params); +int rt_isula_exec(const char *id, const char *runtime, const rt_exec_params_t *params, int *exit_code); + + +int rt_isula_status(const char *name, const char *runtime, const rt_status_params_t *params, + struct engine_container_status_info *status); +int rt_isula_attach(const char *id, const char *runtime, const rt_attach_params_t *params); +int rt_isula_update(const char *id, const char *runtime, const rt_update_params_t *params); +int rt_isula_pause(const char *id, const char *runtime, const rt_pause_params_t *params); +int rt_isula_resume(const char *id, const char *runtime, const rt_resume_params_t *params); +int rt_isula_listpids(const char *name, const char *runtime, const rt_listpids_params_t *params, + rt_listpids_out_t *out); +int rt_isula_resources_stats(const char *name, const char *runtime, const rt_stats_params_t *params, + struct engine_container_resources_stats_info *rs_stats); +int rt_isula_resize(const char *id, const char *runtime, const rt_resize_params_t *params); +int rt_isula_exec_resize(const char *id, const char *runtime, const rt_exec_resize_params_t *params); + + +#ifdef __cplusplus +} +#endif + +#endif /* ISULA_RT_OPS_H */ diff --git a/src/runtime/lcr/lcr_rt_ops.c b/src/runtime/lcr/lcr_rt_ops.c index 8f17e2b..5b31974 100644 --- a/src/runtime/lcr/lcr_rt_ops.c +++ b/src/runtime/lcr/lcr_rt_ops.c @@ -20,7 +20,6 @@ #include "lcr_rt_ops.h" #include "log.h" #include "engine.h" -#include "callback.h" #include "error.h" #include "isulad_config.h" #include "runtime.h" @@ -58,7 +57,9 @@ int rt_lcr_create(const char *name, const char *runtime, const rt_create_params_ if (!engine_ops->engine_create_op(name, runtime_root, params->oci_config_data)) { ERROR("Failed to create container"); const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Create container error: %s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); @@ -67,7 +68,7 @@ int rt_lcr_create(const char *name, const char *runtime, const rt_create_params_ } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } free(runtime_root); @@ -130,7 +131,9 @@ int rt_lcr_start(const char *name, const char *runtime, const rt_start_params_t if (!engine_ops->engine_start_op(&request)) { const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Start container error: %s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); @@ -146,7 +149,7 @@ int rt_lcr_start(const char *name, const char *runtime, const rt_start_params_t goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -171,7 +174,9 @@ int rt_lcr_clean_resource(const char *name, const char *runtime, const rt_clean_ if (!engine_ops->engine_clean_op(name, params->rootpath, params->logpath, params->loglevel, params->pid)) { const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_try_set_error_message("Clean resource container error;%s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); @@ -180,7 +185,7 @@ int rt_lcr_clean_resource(const char *name, const char *runtime, const rt_clean_ } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -223,8 +228,11 @@ int rt_lcr_rm(const char *name, const char *runtime, const rt_rm_params_t *param } if (!engine_ops->engine_delete_op(name, params->rootpath)) { + const char *tmpmsg = NULL; ret = -1; - const char *tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Runtime delete container error: %s", (tmpmsg != NULL && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); ERROR("Runtime delete container error: %s", @@ -241,7 +249,7 @@ int rt_lcr_rm(const char *name, const char *runtime, const rt_rm_params_t *param } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -263,13 +271,12 @@ int rt_lcr_status(const char *name, const char *runtime, const rt_status_params_ nret = engine_ops->engine_get_container_status_op(name, params->rootpath, status); if (nret != 0) { - engine_ops->engine_clear_errmsg_op(); ret = -1; goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -291,13 +298,12 @@ int rt_lcr_resources_stats(const char *name, const char *runtime, const rt_stats nret = engine_ops->engine_get_container_resources_stats_op(name, params->rootpath, rs_stats); if (nret != 0) { - engine_ops->engine_clear_errmsg_op(); ret = -1; goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -359,14 +365,16 @@ int rt_lcr_exec(const char *id, const char *runtime, const rt_exec_params_t *par request.lcrpath = params->rootpath; request.logpath = params->logpath; request.loglevel = params->loglevel; - request.args = (const char **)params->spec->args; - request.args_len = params->spec->args_len; - request.env = (const char **)params->spec->env; - request.env_len = params->spec->env_len; + if (params->spec != NULL) { + request.args = (const char **)params->spec->args; + request.args_len = params->spec->args_len; + request.env = (const char **)params->spec->env; + request.env_len = params->spec->env_len; + } request.console_fifos = params->console_fifos; request.timeout = params->timeout; request.suffix = params->suffix; - if (params->spec->user != NULL) { + if (params->spec != NULL && params->spec->user != NULL) { if (generate_user_string_by_uid_gid(params->spec->user, &user) != 0) { ret = -1; goto out; @@ -376,7 +384,9 @@ int rt_lcr_exec(const char *id, const char *runtime, const rt_exec_params_t *par if (!engine_ops->engine_exec_op(&request, exit_code)) { const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Exec container error;%s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); util_contain_errmsg(g_isulad_errmsg, exit_code); @@ -385,7 +395,7 @@ int rt_lcr_exec(const char *id, const char *runtime, const rt_exec_params_t *par } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } free(user); @@ -407,14 +417,16 @@ int rt_lcr_pause(const char *name, const char *runtime, const rt_pause_params_t if (!engine_ops->engine_pause_op(name, params->rootpath)) { DEBUG("Pause container %s failed", name); const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Pause container error;%s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); ret = -1; goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -435,7 +447,9 @@ int rt_lcr_resume(const char *name, const char *runtime, const rt_resume_params_ if (!engine_ops->engine_resume_op(name, params->rootpath)) { DEBUG("Resume container %s failed", name); const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Resume container error;%s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); @@ -443,7 +457,7 @@ int rt_lcr_resume(const char *name, const char *runtime, const rt_resume_params_ goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -465,14 +479,16 @@ int rt_lcr_attach(const char *name, const char *runtime, const rt_attach_params_ (char *)params->stderr)) { ERROR("attach failed"); const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Attach container error;%s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); ret = -1; goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -514,14 +530,16 @@ int rt_lcr_update(const char *id, const char *runtime, const rt_update_params_t if (!engine_ops->engine_update_op(id, params->rootpath, &cr)) { DEBUG("Update container %s failed", id); const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Cannot update container %s: %s", id, (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); ret = -1; goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -532,24 +550,32 @@ int rt_lcr_listpids(const char *name, const char *runtime, const rt_listpids_par int ret = 0; struct engine_operation *engine_ops = NULL; + if (out == NULL) { + ERROR("Invalid arguments"); + ret = -1; + goto out; + } + engine_ops = engines_get_handler(runtime); if (engine_ops == NULL || engine_ops->engine_get_container_pids_op == NULL) { - DEBUG("Failed to get engine top operations"); + ERROR("Failed to get engine top operations"); ret = -1; goto out; } if (!engine_ops->engine_get_container_pids_op(name, params->rootpath, &(out->pids), &(out->pids_len))) { - DEBUG("Top container %s failed", name); + ERROR("Top container %s failed", name); const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Runtime top container error: %s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); ret = -1; goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -570,7 +596,9 @@ int rt_lcr_resize(const char *id, const char *runtime, const rt_resize_params_t if (!engine_ops->engine_resize_op(id, params->rootpath, params->height, params->width)) { DEBUG("resize container %s failed", id); const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Resize container error;%s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); @@ -579,7 +607,7 @@ int rt_lcr_resize(const char *id, const char *runtime, const rt_resize_params_t goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; @@ -600,7 +628,9 @@ int rt_lcr_exec_resize(const char *id, const char *runtime, const rt_exec_resize if (!engine_ops->engine_exec_resize_op(id, params->rootpath, params->suffix, params->height, params->width)) { DEBUG("exec resize container %s failed", id); const char *tmpmsg = NULL; - tmpmsg = engine_ops->engine_get_errmsg_op(); + if (engine_ops->engine_get_errmsg_op != NULL) { + tmpmsg = engine_ops->engine_get_errmsg_op(); + } isulad_set_error_message("Resize container error;%s", (tmpmsg && strcmp(tmpmsg, DEF_SUCCESS_STR)) ? tmpmsg : DEF_ERR_RUNTIME_STR); @@ -608,7 +638,7 @@ int rt_lcr_exec_resize(const char *id, const char *runtime, const rt_exec_resize goto out; } out: - if (engine_ops != NULL) { + if (engine_ops != NULL && engine_ops->engine_clear_errmsg_op != NULL) { engine_ops->engine_clear_errmsg_op(); } return ret; diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index e9906de..4f0a515 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -25,6 +25,7 @@ #include "log.h" #include "utils.h" #include "lcr_rt_ops.h" +#include "isula_rt_ops.h" static const struct rt_ops g_lcr_rt_ops = { .detect = rt_lcr_detect, @@ -45,8 +46,28 @@ static const struct rt_ops g_lcr_rt_ops = { .rt_exec_resize = rt_lcr_exec_resize, }; +static const struct rt_ops g_isula_rt_ops = { + .detect = rt_isula_detect, + .rt_create = rt_isula_create, + .rt_start = rt_isula_start, + .rt_restart = rt_isula_restart, + .rt_clean_resource = rt_isula_clean_resource, + .rt_rm = rt_isula_rm, + .rt_status = rt_isula_status, + .rt_exec = rt_isula_exec, + .rt_pause = rt_isula_pause, + .rt_resume = rt_isula_resume, + .rt_attach = rt_isula_attach, + .rt_update = rt_isula_update, + .rt_listpids = rt_isula_listpids, + .rt_resources_stats = rt_isula_resources_stats, + .rt_resize = rt_isula_resize, + .rt_exec_resize = rt_isula_exec_resize, +}; + static const struct rt_ops *g_rt_ops[] = { - &g_lcr_rt_ops + &g_lcr_rt_ops, + &g_isula_rt_ops, }; static const size_t g_rt_nums = sizeof(g_rt_ops) / sizeof(struct rt_ops *); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 161fb0b..09780da 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -36,11 +36,15 @@ typedef struct _rt_create_params_t { const char *stdin; const char *stdout; const char *stderr; + const char *exit_fifo; + bool tty; + bool open_stdin; } rt_create_params_t; typedef struct _rt_start_params_t { const char *rootpath; + const char *state; bool tty; bool open_stdin; @@ -73,6 +77,7 @@ typedef struct _rt_rm_params_t { typedef struct _rt_status_params_t { const char *rootpath; + const char *state; } rt_status_params_t; typedef struct _rt_stats_params_t { @@ -81,6 +86,7 @@ typedef struct _rt_stats_params_t { typedef struct _rt_exec_params_t { const char *rootpath; + const char *state; const char *logpath; const char *loglevel; const char **console_fifos; @@ -91,10 +97,12 @@ typedef struct _rt_exec_params_t { typedef struct _rt_pause_params_t { const char *rootpath; + const char *state; } rt_pause_params_t; typedef struct _rt_resume_params_t { const char *rootpath; + const char *state; } rt_resume_params_t; typedef struct _rt_attach_params_t { diff --git a/src/services/callback.h b/src/services/callback.h index 4fcdc02..05af4f1 100644 --- a/src/services/callback.h +++ b/src/services/callback.h @@ -19,6 +19,7 @@ #include "console.h" #include "container_get_id_request.h" #include "container_get_id_response.h" +#include "container_get_runtime_response.h" #include "container_create_request.h" #include "container_create_response.h" #include "container_start_request.h" @@ -90,6 +91,8 @@ typedef struct { int(*get_id)(const container_get_id_request *request, container_get_id_response **response); + int(*get_runtime)(const char *real_id, container_get_runtime_response **response); + int(*create)(const container_create_request *request, container_create_response **response); int(*start)(const container_start_request *request, container_start_response **response, diff --git a/src/services/cri/cri_container.cc b/src/services/cri/cri_container.cc index ec408c7..c7c8201 100644 --- a/src/services/cri/cri_container.cc +++ b/src/services/cri/cri_container.cc @@ -85,6 +85,33 @@ cleanup: return realID; } +std::string CRIRuntimeServiceImpl::GetContainerOrSandboxRuntime(const std::string &realID, Errors &error) +{ + std::string runtime; + if (m_cb == nullptr || m_cb->container.get_runtime == nullptr) { + error.SetError("Unimplemented callback"); + return runtime; + } + container_get_runtime_response *response { nullptr }; + + if (m_cb->container.get_runtime(realID.c_str(), &response) != 0) { + if (response != nullptr && response->errmsg != nullptr) { + error.SetError(response->errmsg); + } else { + error.SetError("Failed to call get id callback"); + } + goto cleanup; + } + + if (response->runtime != nullptr) { + runtime = response->runtime; + } + +cleanup: + free_container_get_runtime_response(response); + return runtime; +} + void CRIRuntimeServiceImpl::GetContainerTimeStamps(container_inspect *inspect, int64_t *createdAt, int64_t *startedAt, int64_t *finishedAt, Errors &err) { @@ -155,6 +182,19 @@ container_config *CRIRuntimeServiceImpl::GenerateCreateContainerCustomConfig( } } + if (append_json_map_string_string(custom_config->annotations, + CRIHelpers::Constants::CONTAINER_TYPE_ANNOTATION_KEY.c_str(), + CRIHelpers::Constants::CONTAINER_TYPE_ANNOTATION_CONTAINER.c_str())) { + error.SetError("Append map string string failed"); + goto cleanup; + } + if (append_json_map_string_string(custom_config->annotations, + CRIHelpers::Constants::SANDBOX_ID_ANNOTATION_KEY.c_str(), + realPodSandboxID.c_str())) { + error.SetError("Append map string string failed"); + goto cleanup; + } + if (append_json_map_string_string(custom_config->labels, CRIHelpers::Constants::SANDBOX_ID_LABEL_KEY.c_str(), realPodSandboxID.c_str())) { error.SetError("Append map string string failed"); @@ -285,7 +325,7 @@ cleanup: container_create_request *CRIRuntimeServiceImpl::GenerateCreateContainerRequest( const std::string &realPodSandboxID, const runtime::v1alpha2::ContainerConfig &containerConfig, - const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, Errors &error) + const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, const std::string &podSandboxRuntime, Errors &error) { struct parser_context ctx { OPT_GEN_SIMPLIFY, 0 @@ -301,7 +341,9 @@ container_create_request *CRIRuntimeServiceImpl::GenerateCreateContainerRequest( std::string cname = CRINaming::MakeContainerName(podSandboxConfig, containerConfig); request->id = util_strdup_s(cname.c_str()); - request->runtime = util_strdup_s(CRIHelpers::Constants::DEFAULT_RUNTIME_NAME.c_str()); + if (!podSandboxRuntime.empty()) { + request->runtime = util_strdup_s(podSandboxRuntime.c_str()); + } if (!containerConfig.image().image().empty()) { request->image = util_strdup_s(containerConfig.image().image().c_str()); @@ -357,6 +399,7 @@ std::string CRIRuntimeServiceImpl::CreateContainer(const std::string &podSandbox Errors &error) { std::string response_id { "" }; + std::string podSandboxRuntime { "" }; if (m_cb == nullptr || m_cb->container.create == nullptr) { error.SetError("Unimplemented callback"); @@ -372,7 +415,9 @@ std::string CRIRuntimeServiceImpl::CreateContainer(const std::string &podSandbox goto cleanup; } - request = GenerateCreateContainerRequest(realPodSandboxID, containerConfig, podSandboxConfig, error); + podSandboxRuntime = GetContainerOrSandboxRuntime(realPodSandboxID, error); + + request = GenerateCreateContainerRequest(realPodSandboxID, containerConfig, podSandboxConfig, podSandboxRuntime, error); if (error.NotEmpty()) { error.SetError("Failed to generate create container request"); goto cleanup; @@ -388,6 +433,7 @@ std::string CRIRuntimeServiceImpl::CreateContainer(const std::string &podSandbox } response_id = response->id; + cleanup: free_container_create_request(request); free_container_create_response(response); @@ -877,6 +923,10 @@ void CRIRuntimeServiceImpl::ContainerStatsToGRPC( container_stats_response *response, std::vector> *containerstats, Errors &error) { + if (response == nullptr) { + return; + } + for (size_t i {}; i < response->container_stats_len; i++) { using ContainerStatsPtr = std::unique_ptr; ContainerStatsPtr container(new (std::nothrow) runtime::v1alpha2::ContainerStats); diff --git a/src/services/cri/cri_helpers.cc b/src/services/cri/cri_helpers.cc index 82b762e..92d4054 100644 --- a/src/services/cri/cri_helpers.cc +++ b/src/services/cri/cri_helpers.cc @@ -45,6 +45,10 @@ const std::string Constants::DOCKER_PULLABLE_IMAGEID_PREFIX { "docker-pullable:/ const std::string Constants::RUNTIME_READY { "RuntimeReady" }; const std::string Constants::NETWORK_READY { "NetworkReady" }; const std::string Constants::POD_CHECKPOINT_KEY { "cri.sandbox.isulad.checkpoint" }; +const std::string Constants::CONTAINER_TYPE_ANNOTATION_KEY { "io.kubernetes.cri.container-type" }; +const std::string Constants::CONTAINER_TYPE_ANNOTATION_CONTAINER { "container" }; +const std::string Constants::CONTAINER_TYPE_ANNOTATION_SANDBOX { "sandbox" }; +const std::string Constants::SANDBOX_ID_ANNOTATION_KEY { "io.kubernetes.cri.sandbox-id" }; const char *InternalLabelKeys[] = { CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY.c_str(), diff --git a/src/services/cri/cri_helpers.h b/src/services/cri/cri_helpers.h index a22815a..ce3c007 100644 --- a/src/services/cri/cri_helpers.h +++ b/src/services/cri/cri_helpers.h @@ -49,6 +49,10 @@ public: static const std::string NETWORK_READY; static const std::string POD_CHECKPOINT_KEY; static const size_t MAX_CHECKPOINT_KEY_LEN { 250 }; + static const std::string CONTAINER_TYPE_ANNOTATION_KEY; + static const std::string CONTAINER_TYPE_ANNOTATION_CONTAINER; + static const std::string CONTAINER_TYPE_ANNOTATION_SANDBOX; + static const std::string SANDBOX_ID_ANNOTATION_KEY; }; std::string GetDefaultSandboxImage(Errors &err); diff --git a/src/services/cri/cri_runtime_service.h b/src/services/cri/cri_runtime_service.h index b271200..fdd254b 100644 --- a/src/services/cri/cri_runtime_service.h +++ b/src/services/cri/cri_runtime_service.h @@ -68,6 +68,8 @@ public: std::string GetRealContainerOrSandboxID(const std::string &id, bool isSandbox, Errors &error); + std::string GetContainerOrSandboxRuntime(const std::string &realID, Errors &error); + container_inspect *InspectContainer(const std::string &containerID, Errors &err); std::string GetNetNS(const std::string &podSandboxID, Errors &err); @@ -79,7 +81,8 @@ public: std::unique_ptr Status(Errors &error) override; - std::string RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config, Errors &error) override; + std::string RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &runtimeHandler, + Errors &error) override; void StopPodSandbox(const std::string &podSandboxID, Errors &error) override; @@ -218,7 +221,8 @@ private: container_create_request * GenerateCreateContainerRequest(const std::string &realPodSandboxID, const runtime::v1alpha2::ContainerConfig &containerConfig, - const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, Errors &error); + const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, + const std::string &podSandboxRuntime, Errors &error); host_config *GenerateCreateContainerHostConfig(const runtime::v1alpha2::ContainerConfig &containerConfig, Errors &error); int PackCreateContainerHostConfigSecurityContext(const runtime::v1alpha2::ContainerConfig &containerConfig, @@ -246,13 +250,14 @@ private: Errors &error); void StartSandboxContainer(const std::string &response_id, Errors &error); std::string CreateSandboxContainer(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, - std::string &jsonCheckpoint, Errors &error); + std::string &jsonCheckpoint, const std::string &runtimeHandler, Errors &error); container_create_request *GenerateSandboxCreateContainerRequest(const runtime::v1alpha2::PodSandboxConfig &config, - const std::string &image, - std::string &jsonCheckpoint, Errors &error); + const std::string &image, std::string &jsonCheckpoint, + const std::string &runtimeHandler, Errors &error); container_create_request *PackCreateContainerRequest(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, host_config *hostconfig, - container_config *container_config, Errors &error); + container_config *container_config, + const std::string &runtimeHandler, Errors &error); int GetRealSandboxIDToStop(const std::string &podSandboxID, bool &hostNetwork, std::string &name, std::string &ns, std::string &realSandboxID, std::map &stdAnnos, Errors &error); int StopAllContainersInSandbox(const std::string &realSandboxID, Errors &error); diff --git a/src/services/cri/cri_sandbox.cc b/src/services/cri/cri_sandbox.cc index 3f138f9..a8fe3a5 100644 --- a/src/services/cri/cri_sandbox.cc +++ b/src/services/cri/cri_sandbox.cc @@ -217,6 +217,12 @@ void CRIRuntimeServiceImpl::MakeSandboxIsuladConfig(const runtime::v1alpha2::Pod if (error.NotEmpty()) { return; } + if (append_json_map_string_string(custom_config->annotations, + CRIHelpers::Constants::CONTAINER_TYPE_ANNOTATION_KEY.c_str(), + CRIHelpers::Constants::CONTAINER_TYPE_ANNOTATION_SANDBOX.c_str()) != 0) { + error.SetError("Append container type into annotation failed"); + return; + } if (!c.hostname().empty()) { custom_config->hostname = util_strdup_s(c.hostname().c_str()); @@ -301,7 +307,7 @@ void CRIRuntimeServiceImpl::SetupSandboxFiles(const std::string &resolvPath, if (!resolvContentStrs.empty()) { std::string resolvContent = CXXUtils::StringsJoin(resolvContentStrs, "\n") + "\n"; - if (util_write_file(resolvPath.c_str(), resolvContent.c_str(), resolvContent.size()) != 0) { + if (util_write_file(resolvPath.c_str(), resolvContent.c_str(), resolvContent.size(), DEFAULT_SECURE_FILE_MODE) != 0) { error.SetError("Failed to write resolv content"); } } @@ -310,7 +316,8 @@ void CRIRuntimeServiceImpl::SetupSandboxFiles(const std::string &resolvPath, container_create_request *CRIRuntimeServiceImpl::PackCreateContainerRequest( const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, host_config *hostconfig, - container_config *custom_config, Errors &error) + container_config *custom_config, + const std::string &runtimeHandler, Errors &error) { struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; parser_error perror = nullptr; @@ -323,7 +330,11 @@ container_create_request *CRIRuntimeServiceImpl::PackCreateContainerRequest( std::string sandboxName = CRINaming::MakeSandboxName(config.metadata()); create_request->id = util_strdup_s(sandboxName.c_str()); - create_request->runtime = util_strdup_s(CRIHelpers::Constants::DEFAULT_RUNTIME_NAME.c_str()); + + if (!runtimeHandler.empty()) { + create_request->runtime = util_strdup_s(runtimeHandler.c_str()); + } + create_request->image = util_strdup_s(image.c_str()); create_request->hostconfig = host_config_generate_json(hostconfig, &ctx, &perror); @@ -348,6 +359,7 @@ error_out: container_create_request *CRIRuntimeServiceImpl::GenerateSandboxCreateContainerRequest( const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, std::string &jsonCheckpoint, + const std::string &runtimeHandler, Errors &error) { container_create_request *create_request = nullptr; @@ -388,7 +400,7 @@ container_create_request *CRIRuntimeServiceImpl::GenerateSandboxCreateContainerR goto error_out; } - create_request = PackCreateContainerRequest(config, image, hostconfig, custom_config, error); + create_request = PackCreateContainerRequest(config, image, hostconfig, custom_config, runtimeHandler, error); if (create_request == nullptr) { error.SetError("Failed to pack create container request"); goto error_out; @@ -406,11 +418,12 @@ cleanup: std::string CRIRuntimeServiceImpl::CreateSandboxContainer(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, std::string &jsonCheckpoint, + const std::string &runtimeHandler, Errors &error) { std::string response_id { "" }; container_create_request *create_request = - GenerateSandboxCreateContainerRequest(config, image, jsonCheckpoint, error); + GenerateSandboxCreateContainerRequest(config, image, jsonCheckpoint, runtimeHandler, error); if (error.NotEmpty()) { return response_id; } @@ -537,7 +550,9 @@ cleanup: free_container_inspect(inspect_data); } -std::string CRIRuntimeServiceImpl::RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config, Errors &error) +std::string CRIRuntimeServiceImpl::RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config, + const std::string &runtimeHandler, + Errors &error) { std::string response_id; std::string jsonCheckpoint; @@ -555,7 +570,7 @@ std::string CRIRuntimeServiceImpl::RunPodSandbox(const runtime::v1alpha2::PodSan } // Step 2: Create the sandbox container. - response_id = CreateSandboxContainer(config, image, jsonCheckpoint, error); + response_id = CreateSandboxContainer(config, image, jsonCheckpoint, runtimeHandler, error); if (error.NotEmpty()) { goto cleanup; } diff --git a/src/services/cri/cri_services.h b/src/services/cri/cri_services.h index a5a143d..495ec89 100644 --- a/src/services/cri/cri_services.h +++ b/src/services/cri/cri_services.h @@ -69,7 +69,8 @@ public: class PodSandboxManager { public: - virtual std::string RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config, Errors &error) = 0; + virtual std::string RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &runtimeHandler, + Errors &error) = 0; virtual void StopPodSandbox(const std::string &podSandboxID, Errors &error) = 0; diff --git a/src/services/execution/events/collector.c b/src/services/execution/events/collector.c index bbb2d37..0e7dc73 100644 --- a/src/services/execution/events/collector.c +++ b/src/services/execution/events/collector.c @@ -32,6 +32,8 @@ #include "isulad_config.h" #include "libisulad.h" #include "containers_store.h" +#include "container_unix.h" +#include "image.h" static struct context_lists g_context_lists; @@ -126,6 +128,300 @@ static container_events_type_t lcrsta2Evetype(int value) return et; } +static const char * const g_isulad_event_strtype[] = { + "exit", "die", "starting", "running", "stopping", "aborting", "freezing", "frozen", "thawed", + "oom", "create", "start", "restart", "stop", "exec_create", "exec_start", "exec_die", "attach", + "kill", "top", "reanme", "archive-path", "extract-to-dir", "update", "pause", "unpause", "export", + "resize", "paused1", +}; + +/* isulad event sta2str */ +static const char *isulad_event_sta2str(container_events_type_t sta) +{ + if (sta > EVENTS_TYPE_PAUSED1) { + return NULL; + } + + return g_isulad_event_strtype[sta]; +} + +static const char * const g_isulad_image_event_strtype[] = { + "load", "remove", "pull", "login", "logout" +}; + +static const char *isulad_image_event_sta2str(image_events_type_t sta) +{ + if (sta > EVENTS_TYPE_IMAGE_LOGOUT) { + return NULL; + } + + return g_isulad_image_event_strtype[sta]; +} + +static void supplement_msg_for_events_handler(const struct monitord_msg *msg, struct isulad_events_format *format_msg) +{ + if (msg->pid != -1) { + format_msg->has_pid = true; + format_msg->pid = (uint32_t)msg->pid; + } + + format_msg->has_type = true; + format_msg->type = lcrsta2Evetype(msg->value); + if (format_msg->type == EVENTS_TYPE_STOPPED1) { + format_msg->has_exit_status = true; + if (msg->exit_code >= 0) { + format_msg->exit_status = (uint32_t)msg->exit_code; + } else { + format_msg->exit_status = 125; + } + } +} + +static int supplement_operator_for_container_msg(const struct monitord_msg *msg, + struct isulad_events_format *format_msg) +{ +#define OPERATOR_MAX_LEN 50 + int nret = 0; + char opt[OPERATOR_MAX_LEN] = {0x00}; + + if (strlen(msg->args) != 0) { + nret = snprintf(opt, sizeof(opt), "container %s: %s", isulad_event_sta2str(msg->value), msg->args); + } else { + nret = snprintf(opt, sizeof(opt), "container %s", isulad_event_sta2str(msg->value)); + } + if (nret < 0 || nret >= sizeof(opt)) { + return -1; + } + + free(format_msg->opt); + format_msg->opt = util_strdup_s(opt); + + return 0; +} + +static int supplement_pid_for_container_msg(const container_t *cont, const struct monitord_msg *msg, + struct isulad_events_format *format_msg) +{ + int nret = 0; + char info[EXTRA_ANNOTATION_MAX] = {0x00}; + + if (cont->state == NULL || cont->state->state == NULL || cont->state->state->pid <= 0) { + return 0; + } + + nret = snprintf(info, sizeof(info), "pid=%u", cont->state->state->pid); + if (nret < 0 || nret >= sizeof(info)) { + return -1; + } + + if (util_array_append(&format_msg->annotations, info) != 0) { + ERROR("Out of memory"); + return -1; + } + + return 0; +} + +static int supplement_exitcode_for_container_msg(const container_t *cont, const struct monitord_msg *msg, + struct isulad_events_format *format_msg) +{ + int nret = 0; + int exit_code = 0; + char info[EXTRA_ANNOTATION_MAX] = {0x00}; + + if (format_msg->exit_status != 0) { + exit_code = format_msg->exit_status; + } else if (cont->state != NULL && cont->state->state != NULL && cont->state->state->exit_code != 0) { + exit_code = cont->state->state->exit_code; + } + + if (exit_code == 0) { + return 0; + } + + nret = snprintf(info, sizeof(info), "exitCode=%u", exit_code); + if (nret < 0 || nret >= sizeof(info)) { + return -1; + } + + if (util_array_append(&format_msg->annotations, info) != 0) { + ERROR("Out of memory"); + return -1; + } + + return 0; +} + +static int supplement_image_for_container_msg(const container_t *cont, const struct monitord_msg *msg, + struct isulad_events_format *format_msg) +{ + int nret = 0; + char info[EXTRA_ANNOTATION_MAX] = {0x00}; + + if (cont->common_config == NULL || cont->common_config->image == NULL) { + return 0; + } + + nret = snprintf(info, sizeof(info), "image=%s", cont->common_config->image); + if (nret < 0 || nret >= sizeof(info)) { + return -1; + } + + if (util_array_append(&format_msg->annotations, info) != 0) { + ERROR("Out of memory"); + return -1; + } + + return 0; +} + +static int supplement_name_for_container_msg(const container_t *cont, const struct monitord_msg *msg, + struct isulad_events_format *format_msg) +{ + int nret = 0; + char info[EXTRA_ANNOTATION_MAX] = {0x00}; + + if (cont->common_config == NULL || cont->common_config->name == NULL) { + return 0; + } + + nret = snprintf(info, sizeof(info), "name=%s", cont->common_config->name); + if (nret < 0 || nret >= sizeof(info)) { + return -1; + } + + if (util_array_append(&format_msg->annotations, info) != 0) { + ERROR("Out of memory"); + return -1; + } + + return 0; +} + +static int supplement_labels_for_container_msg(const container_t *cont, const struct monitord_msg *msg, + struct isulad_events_format *format_msg) +{ + size_t i; + + if (cont->common_config == NULL || + cont->common_config->config->labels == NULL || + cont->common_config->config->labels->len == 0) { + return 0; + } + + for (i = 0; i < cont->common_config->config->labels->len; i++) { + char info[EXTRA_ANNOTATION_MAX] = {0x00}; + int nret = snprintf(info, sizeof(info), "%s=%s", cont->common_config->config->labels->keys[i], + cont->common_config->config->labels->values[i]); + if (nret < 0 || nret >= sizeof(info)) { + return -1; + } + + if (util_array_append(&format_msg->annotations, info) != 0) { + ERROR("Out of memory"); + return -1; + } + } + + return 0; +} + +static int supplement_annotations_for_container_msg(const container_t *cont, const struct monitord_msg *msg, + struct isulad_events_format *format_msg) +{ + + if (supplement_pid_for_container_msg(cont, msg, format_msg) != 0) { + ERROR("Failed to supplement pid info"); + return -1; + } + + if (supplement_exitcode_for_container_msg(cont, msg, format_msg) != 0) { + ERROR("Failed to supplement exitCode info"); + return -1; + } + + if (supplement_image_for_container_msg(cont, msg, format_msg) != 0) { + ERROR("Failed to supplement image info"); + return -1; + } + + if (supplement_name_for_container_msg(cont, msg, format_msg) != 0) { + ERROR("Failed to supplement name info"); + return -1; + } + + if (supplement_labels_for_container_msg(cont, msg, format_msg) != 0) { + ERROR("Failed to supplement label info"); + return -1; + } + + if (strlen(msg->extra_annations) != 0) { + if (util_array_append(&format_msg->annotations, msg->extra_annations) != 0) { + ERROR("Failed to supplement extra annations info"); + return -1; + } + } + + format_msg->annotations_len = util_array_len((const char **)format_msg->annotations); + + return 0; +} + +static int supplement_msg_for_container(struct monitord_msg *msg, struct isulad_events_format *format_msg) +{ + int ret = 0; + container_t *cont = containers_store_get(msg->name); + if (cont == NULL) { + ERROR("No such container:%s", msg->name); + ret = -1; + goto out; + } + + // pid & exit_status parameter for events handler + supplement_msg_for_events_handler(msg, format_msg); + + if (cont->common_config != NULL && cont->common_config->id != NULL) { + format_msg->id = util_strdup_s(cont->common_config->id); + } + + if (supplement_operator_for_container_msg(msg, format_msg) != 0) { + ERROR("Failed to supplement operator info"); + ret = -1; + goto out; + } + + if (supplement_annotations_for_container_msg(cont, msg, format_msg) != 0) { + ERROR("Failed to supplement annotations info"); + ret = -1; + goto out; + } + +out: + container_unref(cont); + return ret; +} + +static int supplement_msg_for_image(struct monitord_msg *msg, struct isulad_events_format *format_msg) +{ +#define OPERATOR_MAX_LEN 50 + int ret = 0; + int nret = 0; + char opt[OPERATOR_MAX_LEN] = {0x00}; + + format_msg->id = util_strdup_s(msg->name); + + nret = snprintf(opt, sizeof(opt), "image %s", isulad_image_event_sta2str(msg->value)); + if (nret < 0 || nret >= sizeof(opt)) { + ERROR("Get operator operator info failed"); + ret = -1; + goto out; + } + format_msg->opt = util_strdup_s(opt); + +out: + return ret; +} + /* format_msg */ static bool format_msg(struct isulad_events_format *r, struct monitord_msg *msg) { @@ -147,26 +443,16 @@ static bool format_msg(struct isulad_events_format *r, struct monitord_msg *msg) r->has_pid = false; switch (msg->type) { - case monitord_msg_state: - r->id = msg->name; - if (msg->pid != -1) { - r->has_pid = true; - r->pid = (uint32_t)msg->pid; - } - r->has_type = true; - r->type = lcrsta2Evetype(msg->value); - if (r->type == EVENTS_TYPE_STOPPED1) { - r->has_exit_status = true; - if (msg->exit_code >= 0) { - r->exit_status = (uint32_t)msg->exit_code; - } else { - r->exit_status = 125; - } + case MONITORD_MSG_STATE: + if (msg->event_type == CONTAINER_EVENT) { + supplement_msg_for_container(msg, r); + } else if (msg->event_type == IMAGE_EVENT) { + supplement_msg_for_image(msg, r); } ret = true; break; - case monitord_msg_priority: - case monitord_msg_exit_code: + case MONITORD_MSG_PRIORITY: + case MONITORD_MSG_EXIT_CODE: default: /* ignore garbage */ ret = false; @@ -176,20 +462,6 @@ static bool format_msg(struct isulad_events_format *r, struct monitord_msg *msg) return ret; } -static const char * const g_isulad_event_strtype[] = { - "EXIT", "STOPPED", "STARTING", "RUNNING", "STOPPING", "ABORTING", "FREEZING", - "FROZEN", "THAWED", "OOM", "CREATE", "START", "EXEC_ADDED", "PAUSED1", -}; - -/* isulad event sta2str */ -static const char *isulad_event_sta2str(container_events_type_t sta) -{ - if (sta > EVENTS_TYPE_PAUSED1) { - return NULL; - } - return g_isulad_event_strtype[sta]; -} - /* isulad monitor fifo send */ static void isulad_monitor_fifo_send(const struct monitord_msg *msg, const char *statedir) { @@ -231,16 +503,20 @@ out: } } -/* isulad monitor send event */ -int isulad_monitor_send_event(const char *name, runtime_state_t state, int pid, int exit_code) +/* isulad monitor send container event */ +int isulad_monitor_send_container_event(const char *name, runtime_state_t state, int pid, int exit_code, + const char *args, const char *extra_annations) { int ret = 0; char *statedir = NULL; struct monitord_msg msg = { - .type = monitord_msg_state, + .type = MONITORD_MSG_STATE, + .event_type = CONTAINER_EVENT, .value = state, .pid = -1, - .exit_code = -1 + .exit_code = -1, + .args = {0x00}, + .extra_annations = {0x00} }; if (name == NULL) { @@ -257,7 +533,18 @@ int isulad_monitor_send_event(const char *name, runtime_state_t state, int pid, } (void)strncpy(msg.name, name, sizeof(msg.name) - 1); - msg.name[sizeof(msg.name) - 1] = 0; + msg.name[sizeof(msg.name) - 1] = '\0'; + + if (args != NULL) { + (void)strncpy(msg.args, args, sizeof(msg.args) - 1); + msg.args[sizeof(msg.args) - 1] = '\0'; + } + + if (extra_annations != NULL) { + (void)strncpy(msg.extra_annations, extra_annations, sizeof(msg.extra_annations) - 1); + msg.extra_annations[sizeof(msg.extra_annations) - 1] = '\0'; + } + if (pid > 0) { msg.pid = pid; } @@ -272,68 +559,142 @@ out: return ret; } +/* isulad monitor send image event */ +int isulad_monitor_send_image_event(const char *name, image_state_t state) +{ + int ret = 0; + char *statedir = NULL; + + struct monitord_msg msg = { + .type = MONITORD_MSG_STATE, + .event_type = IMAGE_EVENT, + .value = state, + .args = {0x00}, + .extra_annations = {0x00} + }; + + if (name == NULL) { + CRIT("Invalid input arguments"); + ret = -1; + goto out; + } + + statedir = conf_get_isulad_statedir(); + if (statedir == NULL) { + CRIT("Can not get isulad root path"); + ret = -1; + goto out; + } + + (void)strncpy(msg.name, name, sizeof(msg.name) - 1); + msg.name[sizeof(msg.name) - 1] = '\0'; + + isulad_monitor_fifo_send(&msg, statedir); + +out: + free(statedir); + return ret; +} + +static int calculate_annaotation_info_len(const struct isulad_events_format *events) +{ + size_t i; + size_t len = 0; + for (i = 0; i < events->annotations_len; i++) { + len += strlen(events->annotations[i]); + } + len += events->annotations_len * 2; // length of ", " and "()" + len += 1; // length of '\0' + + return len; +} + /* write events log */ static int write_events_log(const struct isulad_events_format *events) { -#define PID_PREFIX ", Pid: " -#define EXIT_CODE_PREFIX ", ExitCode: " - int ret = 0; - int nret = 0; - char *pid_str = NULL; - char *exit_status_str = NULL; - + size_t i; + char *annotation = NULL; + size_t len = 0; if (events == NULL) { goto out; } - if (events->has_pid) { - nret = asprintf(&pid_str, "%s%u", PID_PREFIX, events->pid); - if (nret < 0) { - ERROR("Sprintf pid failed"); + len = calculate_annaotation_info_len(events); + if (len == 1) { + EVENT("Event: {Object: %s, Type: %s}", events->id, events->opt); + } else { + annotation = (char *)util_common_calloc_s(len); + if (annotation == NULL) { + ERROR("Out of memory"); ret = -1; goto out; } - } - if (events->has_exit_status) { - nret = asprintf(&exit_status_str, "%s%u", EXIT_CODE_PREFIX, events->exit_status); - if (nret < 0) { - ERROR("Sprintf exit status failed"); - ret = -1; - goto out; + (void)strcat(annotation, "("); + for (i = 0; i < events->annotations_len; i++) { + (void)strcat(annotation, events->annotations[i]); + if (i != events->annotations_len - 1) { + (void)strcat(annotation, ", "); + } } - } + (void)strcat(annotation, ")"); - EVENT("Event: {Object: %s, Type: %s%s%s}", events->id, - (events->has_type ? isulad_event_sta2str((container_events_type_t)events->type) : "-"), - (events->has_pid ? pid_str : ""), (events->has_exit_status ? exit_status_str : "")); + EVENT("Event: {Object: %s, Type: %s %s}", events->id, events->opt, annotation); + } out: - free(pid_str); - free(exit_status_str); + free(annotation); return ret; } /* events copy */ -static void event_copy(const struct isulad_events_format *src, struct isulad_events_format *dest) +static int event_copy(const struct isulad_events_format *src, struct isulad_events_format *dest) { + size_t i; if (src == NULL || dest == NULL) { - return; + return 0; } - free(dest->id); - dest->id = util_strdup_s(src->id); - dest->has_type = src->has_type; - dest->type = src->type; - dest->has_pid = src->has_pid; - dest->pid = src->pid; - dest->has_exit_status = src->has_exit_status; - dest->exit_status = src->exit_status; dest->timestamp.has_seconds = src->timestamp.has_seconds; dest->timestamp.seconds = src->timestamp.seconds; dest->timestamp.has_nanos = src->timestamp.has_nanos; dest->timestamp.nanos = src->timestamp.nanos; + + if (src->id != NULL) { + free(dest->id); + dest->id = util_strdup_s(src->id); + } + + if (src->opt != NULL) { + free(dest->opt); + dest->opt = util_strdup_s(src->opt); + } + + if (src->annotations_len != 0) { + util_free_array(dest->annotations); + dest->annotations = (char **)util_common_calloc_s(src->annotations_len * sizeof(char *)); + if (dest->annotations == NULL) { + ERROR("Out of memory"); + return -1; + } + + if (dest->annotations) + for (i = 0; i < src->annotations_len; i++) { + dest->annotations[i] = util_strdup_s(src->annotations[i]); + } + dest->annotations_len = src->annotations_len; + } + + dest->has_type = src->has_type; + dest->type = src->type; + + dest->has_pid = src->has_pid; + dest->pid = src->pid; + dest->has_exit_status = src->has_exit_status; + dest->exit_status = src->exit_status; + + return 0; } /* events append */ @@ -362,7 +723,12 @@ static void events_append(const struct isulad_events_format *event) goto unlock; } - event_copy(event, tmpevent); + if (event_copy(event, tmpevent) != 0) { + CRIT("Failed to copy event."); + isulad_events_format_free(tmpevent); + free(newnode); + goto unlock; + } linked_list_add_elem(newnode, tmpevent); linked_list_add_tail(&g_events_buffer.event_list, newnode); @@ -373,7 +739,10 @@ static void events_append(const struct isulad_events_format *event) linked_list_del(firstnode); tmpevent = (struct isulad_events_format *)firstnode->elem; - event_copy(event, tmpevent); + if (event_copy(event, tmpevent) != 0) { + CRIT("Failed to copy event."); + goto unlock; + } linked_list_add_tail(&g_events_buffer.event_list, firstnode); } @@ -668,28 +1037,38 @@ out: /* events handler */ void events_handler(struct monitord_msg *msg) { - struct isulad_events_format events = { 0 }; + struct isulad_events_format *events = NULL; if (msg == NULL) { ERROR("Invalid input arguments"); return; } - if (format_msg(&events, msg) != true) { + events = (struct isulad_events_format *)util_common_calloc_s(sizeof(struct isulad_events_format)); + if (events == NULL) { + ERROR("Out of memory"); return; } + if (format_msg(events, msg) != true) { + ERROR("Failed to format massage"); + goto out; + } + /* post events to events handler */ - if (post_event_to_events_hander(&events)) { - ERROR("Failed to handle %s STOPPED events with pid %d", events.id, events.pid); - return; + if (post_event_to_events_hander(events)) { + ERROR("Failed to handle %s STOPPED events with pid %d", events->id, msg->pid); + goto out; } /* forward events to grpc clients */ - events_forward(&events); + events_forward(events); /* log event into isulad.log */ - (void)write_events_log(&events); + (void)write_events_log(events); + +out: + isulad_events_format_free(events); } /* dup event */ @@ -711,17 +1090,6 @@ struct isulad_events_format *dup_event(const struct isulad_events_format *event) return out; } -/* free event */ -void free_event(struct isulad_events_format *event) -{ - if (event == NULL) { - return; - } - free(event->id); - event->id = NULL; - free(event); - return; -} /* add monitor client */ int add_monitor_client(char *name, const types_timestamp_t *since, const types_timestamp_t *until, @@ -825,4 +1193,3 @@ int newcollector() out: return ret; } - diff --git a/src/services/execution/events/collector.h b/src/services/execution/events/collector.h index c806e0e..e0d06c9 100644 --- a/src/services/execution/events/collector.h +++ b/src/services/execution/events/collector.h @@ -21,6 +21,10 @@ #include "libisulad.h" #include "monitord.h" +#ifdef __cplusplus +extern "C" { +#endif + struct context_lists { pthread_mutex_t context_mutex; struct linked_list context_list; @@ -38,9 +42,14 @@ int events_subscribe(const char *name, const types_timestamp_t *since, const typ struct isulad_events_format *dup_event(const struct isulad_events_format *event); -void free_event(struct isulad_events_format *event); +int isulad_monitor_send_container_event(const char *name, runtime_state_t state, int pid, int exit_code, + const char *args, const char *extra_annations); -int isulad_monitor_send_event(const char *name, runtime_state_t state, int pid, int exit_code); +int isulad_monitor_send_image_event(const char *name, image_state_t state); + +#ifdef __cplusplus +} +#endif #endif /* __COLLECTOR_H */ diff --git a/src/services/execution/events/events_handler.c b/src/services/execution/events/events_handler.c index 3599b44..33a8d6f 100644 --- a/src/services/execution/events/events_handler.c +++ b/src/services/execution/events/events_handler.c @@ -61,7 +61,7 @@ void events_handler_free(events_handler_t *handler) linked_list_for_each_safe(it, &(handler->events_list), next) { event = (struct isulad_events_format *)it->elem; linked_list_del(it); - free_event(event); + isulad_events_format_free(event); free(it); it = NULL; } @@ -184,20 +184,6 @@ static int container_state_changed(container_t *cont, const struct isulad_events } break; - case EVENTS_TYPE_EXIT: - case EVENTS_TYPE_STARTING: - case EVENTS_TYPE_RUNNING1: - case EVENTS_TYPE_STOPPING: - case EVENTS_TYPE_ABORTING: - case EVENTS_TYPE_FREEZING: - case EVENTS_TYPE_FROZEN: - case EVENTS_TYPE_THAWED: - case EVENTS_TYPE_OOM: - case EVENTS_TYPE_CREATE: - case EVENTS_TYPE_START: - case EVENTS_TYPE_EXEC_ADDED: - case EVENTS_TYPE_PAUSED1: - case EVENTS_TYPE_MAX_STATE: default: /* ignore garbage */ break; @@ -231,7 +217,7 @@ static int handle_one(container_t *cont, events_handler_t *handler) ERROR("Failed to change container %s state", cont->common_config->id); } - free_event(events); + isulad_events_format_free(events); events = NULL; free(it); diff --git a/src/services/execution/execute/execution.c b/src/services/execution/execute/execution.c index 40e4376..cd92e03 100644 --- a/src/services/execution/execute/execution.c +++ b/src/services/execution/execute/execution.c @@ -52,6 +52,7 @@ #include "specs_extend.h" #include "utils.h" #include "error.h" +#include "collector.h" static int filter_by_label(const container_t *cont, const container_get_id_request *request) @@ -114,6 +115,22 @@ static void pack_get_id_response(container_get_id_response *response, const char } } +static void pack_get_runtime_response(container_get_runtime_response *response, const char *runtime, uint32_t cc) +{ + if (response == NULL) { + return; + } + + response->cc = cc; + if (g_isulad_errmsg != NULL) { + response->errmsg = util_strdup_s(g_isulad_errmsg); + DAEMON_CLEAR_ERRMSG(); + } + if (runtime != NULL) { + response->runtime = util_strdup_s(runtime); + } +} + /* * This function gets long id of container by name or short id */ @@ -165,6 +182,49 @@ pack_response: return (cc == ISULAD_SUCCESS) ? 0 : -1; } +static int container_get_runtime_cb(const char *real_id, container_get_runtime_response **response) +{ + char *runtime = NULL; + uint32_t cc = ISULAD_SUCCESS; + container_t *cont = NULL; + + DAEMON_CLEAR_ERRMSG(); + if (real_id == NULL || response == NULL) { + ERROR("Invalid NULL input"); + return -1; + } + + *response = util_common_calloc_s(sizeof(container_get_runtime_response)); + if (*response == NULL) { + ERROR("Out of memory"); + cc = ISULAD_ERR_MEMOUT; + goto pack_response; + } + + if (!util_valid_container_id_or_name(real_id)) { + ERROR("Invalid container name: %s", real_id); + isulad_set_error_message("Invalid container name: %s", real_id); + cc = ISULAD_ERR_EXEC; + goto pack_response; + } + + cont = containers_store_get(real_id); + if (cont == NULL) { + cc = ISULAD_ERR_EXEC; + ERROR("No such container: %s", real_id); + isulad_set_error_message("No such container: %s", real_id); + goto pack_response; + } + + runtime = cont->runtime; + +pack_response: + pack_get_runtime_response(*response, runtime, cc); + + container_unref(cont); + return (cc == ISULAD_SUCCESS) ? 0 : -1; +} + static int send_signal_to_process(pid_t pid, unsigned long long start_time, uint32_t signal) { if (util_process_alive(pid, start_time) == false) { @@ -468,9 +528,23 @@ static int mount_dev_tmpfs_for_system_container(const container_t *cont) return -1; } } - if (mount("tmpfs", rootfs_dev_path, "tmpfs", 0, "size=500000,mode=755")) { - ERROR("Failed to mount dev tmpfs on '%s'", rootfs_dev_path); - return -1; + /* set /dev mount size to half of container memory limit */ + if (cont->hostconfig->memory > 0) { + char mnt_opt[MOUNT_PROPERTIES_SIZE] = { 0 }; + nret = snprintf(mnt_opt, sizeof(mnt_opt), "size=%lld,mode=755", (long long int)(cont->hostconfig->memory / 2)); + if (nret < 0 || (size_t)nret >= sizeof(mnt_opt)) { + ERROR("Out of memory"); + return -1; + } + if (mount("tmpfs", rootfs_dev_path, "tmpfs", 0, mnt_opt) != 0) { + ERROR("Failed to mount dev tmpfs on '%s'", rootfs_dev_path); + return -1; + } + } else { + if (mount("tmpfs", rootfs_dev_path, "tmpfs", 0, "mode=755") != 0) { + ERROR("Failed to mount dev tmpfs on '%s'", rootfs_dev_path); + return -1; + } } if (cont->hostconfig->user_remap != NULL) { unsigned int host_uid = 0; @@ -783,25 +857,18 @@ static int do_start_container(container_t *cont, const char *console_fifos[], bo goto close_exit_fd; } + if (save_oci_config(id, cont->root_path, oci_spec) != 0) { + ERROR("Failed to save container settings"); + ret = -1; + goto close_exit_fd; + } + start_timeout = conf_get_start_timeout(); if (cont->common_config->config != NULL) { tty = cont->common_config->config->tty; open_stdin = cont->common_config->config->open_stdin; } - create_params.bundle = bundle; - create_params.state = cont->state_path; - create_params.oci_config_data = oci_spec; - create_params.terminal = tty; - create_params.stdin = console_fifos[0]; - create_params.stdout = console_fifos[1]; - create_params.stderr = console_fifos[2]; - - if (runtime_create(id, runtime, &create_params) != 0) { - ret = -1; - goto close_exit_fd; - } - if (plugin_event_container_pre_start(cont)) { ERROR("Plugin event pre start failed "); plugin_event_container_post_stop(cont); /* ignore error */ @@ -809,7 +876,24 @@ static int do_start_container(container_t *cont, const char *console_fifos[], bo goto close_exit_fd; } + create_params.bundle = bundle; + create_params.state = cont->state_path; + create_params.oci_config_data = oci_spec; + create_params.terminal = tty; + create_params.stdin = console_fifos[0]; + create_params.stdout = console_fifos[1]; + create_params.stderr = console_fifos[2]; + create_params.exit_fifo = exit_fifo; + create_params.tty = tty; + create_params.open_stdin = open_stdin; + + if (runtime_create(id, runtime, &create_params) != 0) { + ret = -1; + goto close_exit_fd; + } + start_params.rootpath = cont->root_path; + start_params.state = cont->state_path; start_params.tty = tty; start_params.open_stdin = open_stdin; start_params.logpath = engine_log_path; @@ -1074,6 +1158,7 @@ static int container_start_cb(const container_start_request *request, container_ } EVENT("Event: {Object: %s, Type: Running}", id); + (void)isulad_monitor_send_container_event(id, START, -1, 0, NULL, NULL); pack_response: delete_daemon_fifos(fifopath, (const char **)fifos); @@ -1094,9 +1179,11 @@ pack_response: static int kill_with_signal(container_t *cont, uint32_t signal) { int ret = 0; + int nret = 0; const char *id = cont->common_config->id; bool need_unpause = is_paused(cont->state); rt_resume_params_t params = { 0 }; + char annotations[EXTRA_ANNOTATION_MAX] = {0}; if (container_exit_on_next(cont)) { ERROR("Failed to cancel restart manager"); @@ -1125,6 +1212,7 @@ static int kill_with_signal(container_t *cont, uint32_t signal) } if (signal == SIGKILL && need_unpause) { params.rootpath = cont->root_path; + params.state = cont->state_path; if (runtime_resume(id, cont->runtime, ¶ms) != 0) { ERROR("Cannot unpause container: %s", id); ret = -1; @@ -1132,6 +1220,15 @@ static int kill_with_signal(container_t *cont, uint32_t signal) } } + nret = snprintf(annotations, sizeof(annotations), "signal=%d", signal); + if (nret < 0 || (size_t)nret >= sizeof(annotations)) { + ERROR("Failed to get signal string", id); + ret = -1; + goto out; + } + + (void)isulad_monitor_send_container_event(id, KILL, -1, 0, NULL, annotations); + out: return ret; } @@ -1386,6 +1483,8 @@ static int container_restart_cb(const container_restart_request *request, } EVENT("Event: {Object: %s, Type: Restarted}", id); + (void)isulad_monitor_send_container_event(id, RESTART, -1, 0, NULL, NULL); + pack_response: pack_restart_response(*response, cc, id); container_unref(cont); @@ -1475,6 +1574,7 @@ static int container_stop_cb(const container_stop_request *request, } INFO("Stoped Container:%s", id); + (void)isulad_monitor_send_container_event(id, STOP, -1, 0, NULL, NULL); pack_response: pack_stop_response(*response, cc, id); @@ -1686,6 +1786,8 @@ static int do_cleanup_container_resources(container_t *cont) goto out; } + umount_share_shm(cont); + umount_host_channel(cont->hostconfig->host_channel); if (do_runtime_rm_helper(id, runtime, rootpath) != 0) { @@ -1876,6 +1978,7 @@ pack_response: void container_callback_init(service_container_callback_t *cb) { cb->get_id = container_get_id_cb; + cb->get_runtime = container_get_runtime_cb; cb->create = container_create_cb; cb->start = container_start_cb; cb->stop = container_stop_cb; diff --git a/src/services/execution/execute/execution_create.c b/src/services/execution/execute/execution_create.c index 9e12bdd..15180da 100644 --- a/src/services/execution/execute/execution_create.c +++ b/src/services/execution/execute/execution_create.c @@ -43,6 +43,59 @@ #include "utils.h" #include "error.h" #include "constants.h" +#include "namespace.h" +#include "collector.h" + +static int runtime_check(const char *name, bool *runtime_res) +{ + int ret = 0; + struct service_arguments *args = NULL; + defs_map_string_object_runtimes *runtimes = NULL; + + if (isulad_server_conf_rdlock()) { + ret = -1; + goto out; + } + + args = conf_get_server_conf(); + if (args == NULL) { + ERROR("Failed to get isulad server config"); + ret = -1; + goto unlock_out; + } + + if (args->json_confs != NULL) { + runtimes = args->json_confs->runtimes; + } + if (runtimes == NULL) { + EVENT("isulad runtimes param is null"); + goto unlock_out; + } + + size_t runtime_nums = runtimes->len; + size_t i; + for (i = 0; i < runtime_nums; i++) { + if (strcmp(name, runtimes->keys[i]) == 0) { + *runtime_res = true; + goto unlock_out; + } + } +unlock_out: + if (isulad_server_conf_unlock()) { + ERROR("Failed to unlock isulad server config"); + ret = -1; + } +out: + if (strcmp(name, "runc") == 0 || strcmp(name, "lcr") == 0) { + *runtime_res = true; + } + + if (strcmp(name, "kata-runtime") == 0) { + *runtime_res = true; + } + + return ret; +} static int create_request_check(const container_create_request *request) { @@ -68,20 +121,6 @@ static int create_request_check(const container_create_request *request) goto out; } - if (request->runtime == NULL) { - ERROR("Receive NULL Request runtime"); - ret = -1; - goto out; - } - - if (!util_valid_runtime_name(request->runtime)) { - ERROR("Invalid runtime name:%s", request->runtime); - isulad_set_error_message("Invalid runtime name (%s), only \"lcr\" supported.", - request->runtime); - ret = -1; - goto out; - } - if (request->hostconfig == NULL) { ERROR("Receive NULL Request hostconfig"); ret = -1; @@ -251,12 +290,6 @@ static int merge_config_for_syscontainer(const container_create_request *request return 0; } - if (merge_network(host_spec, request->rootfs, container_spec->hostname) != 0) { - ERROR("Failed to merge network config"); - ret = -1; - goto out; - } - if (append_json_map_string_string(oci_spec->annotations, "rootfs.mount", request->rootfs)) { ERROR("Realloc annotations failed"); ret = -1; @@ -551,6 +584,46 @@ void umount_host_channel(const host_config_host_channel *host_channel) } } +void umount_share_shm(container_t *cont) +{ + if (has_mount_for(cont, "/dev/shm")) { + return; + } + if (cont->hostconfig == NULL) { + return; + } + if (cont->hostconfig->ipc_mode == NULL || is_shareable(cont->hostconfig->ipc_mode)) { + if (cont->common_config == NULL || cont->common_config->shm_path == NULL) { + return; + } + + INFO("Umounting share shm: %s", cont->common_config->shm_path); + if (umount2(cont->common_config->shm_path, MNT_DETACH)) { + SYSERROR("Failed to umount the target: %s", cont->common_config->shm_path); + } + } +} + +static void umount_shm_by_configs(host_config *host_spec, container_config_v2_common_config *v2_spec) +{ + container_t *cont = NULL; + + cont = util_common_calloc_s(sizeof(container_t)); + if (cont == NULL) { + ERROR("Out of memory"); + return; + } + cont->common_config = v2_spec; + cont->hostconfig = host_spec; + + umount_share_shm(cont); + + cont->common_config = NULL; + cont->hostconfig = NULL; + + free(cont); +} + static int create_container_root_dir(const char *id, const char *runtime_root) { int ret = 0; @@ -685,9 +758,27 @@ static int get_request_image_info(const container_create_request *request, char static int preparate_runtime_environment(const container_create_request *request, const char *id, char **runtime, char **runtime_root, uint32_t *cc) { - *runtime = get_runtime_from_request(request); + bool runtime_res = false; + + if (request->runtime) { + *runtime = get_runtime_from_request(request); + } else { + *runtime = conf_get_default_runtime(); + } + if (*runtime == NULL) { - *cc = ISULAD_ERR_INPUT; + *runtime = util_strdup_s(DEFAULT_RUNTIME_NAME); + } + + if (runtime_check(*runtime, &runtime_res) != 0) { + ERROR("Runtimes param check failed"); + return -1; + } + + if (!runtime_res) { + ERROR("Invalid runtime name:%s", *runtime); + isulad_set_error_message("Invalid runtime name (%s).", + *runtime); return -1; } @@ -771,6 +862,9 @@ int container_create_cb(const container_create_request *request, cc = ISULAD_ERR_INPUT; goto clean_container_root_dir; } + // update runtime of host config + free(host_spec->runtime); + host_spec->runtime = util_strdup_s(runtime); v2_spec = util_common_calloc_s(sizeof(container_config_v2_common_config)); if (v2_spec == NULL) { @@ -790,7 +884,6 @@ int container_create_cb(const container_create_request *request, v2_spec->config = container_spec; - /* set network config to v2_spec */ if (init_container_network_confs(id, runtime_root, host_spec, v2_spec) != 0) { ERROR("Init Network files failed"); cc = ISULAD_ERR_INPUT; @@ -813,13 +906,24 @@ int container_create_cb(const container_create_request *request, oci_spec = generate_oci_config(host_spec, real_rootfs, v2_spec); if (oci_spec == NULL) { cc = ISULAD_ERR_EXEC; - goto clean_rootfs; + goto umount_shm; + } + + ret = merge_oci_cgroups_path(id, oci_spec, host_spec); + if (ret < 0) { + goto umount_shm; } if (merge_config_for_syscontainer(request, host_spec, v2_spec->config, oci_spec) != 0) { ERROR("Failed to merge config for syscontainer"); cc = ISULAD_ERR_EXEC; - goto clean_rootfs; + goto umount_shm; + } + + if (merge_network(host_spec, request->rootfs, runtime_root, id, container_spec->hostname) != 0) { + ERROR("Failed to merge network config"); + cc = ISULAD_ERR_EXEC; + goto umount_shm; } /* modify oci_spec by plugin. */ @@ -827,7 +931,7 @@ int container_create_cb(const container_create_request *request, ERROR("Plugin event pre create failed"); (void)plugin_event_container_post_remove2(id, oci_spec); /* ignore error */ cc = ISULAD_ERR_EXEC; - goto clean_rootfs; + goto umount_shm; } host_channel = dup_host_channel(host_spec->host_channel); @@ -835,10 +939,10 @@ int container_create_cb(const container_create_request *request, ERROR("Failed to prepare host channel with '%s'", host_spec->host_channel); sleep(111); cc = ISULAD_ERR_EXEC; - goto clean_rootfs; + goto umount_shm; } - if (verify_container_settings(oci_spec)) { + if (verify_container_settings(oci_spec) != 0) { ERROR("Failed to verify container settings"); cc = ISULAD_ERR_EXEC; goto umount_channel; @@ -863,10 +967,13 @@ int container_create_cb(const container_create_request *request, } EVENT("Event: {Object: %s, Type: Created %s}", id, name); + (void)isulad_monitor_send_container_event(id, CREATE, -1, 0, NULL, NULL); goto pack_response; umount_channel: umount_host_channel(host_channel); +umount_shm: + umount_shm_by_configs(host_spec, v2_spec); clean_rootfs: (void)im_remove_container_rootfs(image_type, id); diff --git a/src/services/execution/execute/execution_create.h b/src/services/execution/execute/execution_create.h index 73d5230..5100b7b 100644 --- a/src/services/execution/execute/execution_create.h +++ b/src/services/execution/execute/execution_create.h @@ -28,6 +28,8 @@ int container_create_cb(const container_create_request *request, void umount_host_channel(const host_config_host_channel *host_channel); +void umount_share_shm(container_t *cont); + #ifdef __cplusplus } #endif diff --git a/src/services/execution/execute/execution_extend.c b/src/services/execution/execute/execution_extend.c index b2b3bb2..35c25e1 100644 --- a/src/services/execution/execute/execution_extend.c +++ b/src/services/execution/execute/execution_extend.c @@ -521,7 +521,7 @@ static int do_resume_container(container_t *cont) } params.rootpath = cont->root_path; - + params.state = cont->state_path; if (runtime_resume(id, cont->runtime, ¶ms)) { ERROR("Failed to resume container:%s", id); ret = -1; @@ -670,6 +670,7 @@ static int container_resume_cb(const container_resume_request *request, containe } EVENT("Event: {Object: %s, Type: Resumed}", id); + (void)isulad_monitor_send_container_event(id, UNPAUSE, -1, 0, NULL, NULL); pack_response: pack_resume_response(*response, cc, id); @@ -708,7 +709,7 @@ static int pause_container(container_t *cont) } params.rootpath = cont->root_path; - + params.state = cont->state_path; if (runtime_pause(id, cont->runtime, ¶ms)) { ERROR("Failed to pause container:%s", id); ret = -1; @@ -810,6 +811,7 @@ static int container_pause_cb(const container_pause_request *request, } EVENT("Event: {Object: %s, Type: Paused}", id); + (void)isulad_monitor_send_container_event(id, PAUSE, -1, 0, NULL, NULL); pack_response: pack_pause_response(*response, cc, id); @@ -1053,7 +1055,7 @@ static int do_update_resources(const container_update_request *request, containe } backup_oci_spec = load_oci_config(cont->root_path, id); - if (oci_spec == NULL) { + if (backup_oci_spec == NULL) { ERROR("Failed to load oci config"); ret = -1; goto restore_hostspec; @@ -1173,6 +1175,7 @@ static int container_update_cb(const container_update_request *request, containe } EVENT("Event: {Object: %s, Type: updated}", id); + (void)isulad_monitor_send_container_event(id, CREATE, -1, 0, NULL, NULL); pack_response: pack_update_response(*response, cc, id); @@ -1260,6 +1263,7 @@ static int container_export_cb(const container_export_request *request, containe goto pack_response; } + (void)isulad_monitor_send_container_event(id, EXPORT, -1, 0, NULL, NULL); pack_response: pack_export_response(*response, cc, id); container_unref(cont); @@ -1432,6 +1436,7 @@ static int container_resize_cb(const struct isulad_container_resize_request *req } EVENT("Event: {Object: %s, Type: Resized}", id); + (void)isulad_monitor_send_container_event(id, RESIZE, -1, 0, NULL, NULL); pack_response: pack_resize_response(*response, cc, id); diff --git a/src/services/execution/execute/execution_information.c b/src/services/execution/execute/execution_information.c index e821886..36e4e6d 100644 --- a/src/services/execution/execute/execution_information.c +++ b/src/services/execution/execute/execution_information.c @@ -44,6 +44,7 @@ #include "list.h" #include "utils.h" #include "error.h" +#include "collector.h" static int container_version_cb(const container_version_request *request, container_version_response **response) { @@ -814,6 +815,7 @@ static int container_top_cb(container_top_request *request, container_top_respon (*response)->processes[i] = util_strdup_s(processes[i]); } (*response)->processes_len = util_array_len((const char **)processes); + (void)isulad_monitor_send_container_event(id, TOP, -1, 0, NULL, NULL); pack_response: if (*response != NULL) { @@ -1216,6 +1218,18 @@ static int pack_inspect_general_data(const container_t *cont, container_inspect if (cont->common_config->resolv_conf_path != NULL) { inspect->resolv_conf_path = util_strdup_s(cont->common_config->resolv_conf_path); } + if (cont->common_config->mount_label != NULL) { + inspect->mount_label = util_strdup_s(cont->common_config->mount_label); + } + if (cont->common_config->process_label != NULL) { + inspect->process_label = util_strdup_s(cont->common_config->process_label); + } + + if (cont->common_config->seccomp_profile != NULL) { + inspect->seccomp_profile = util_strdup_s(cont->common_config->seccomp_profile); + } + + inspect->no_new_privileges = cont->common_config->no_new_privileges; if (mount_point_to_inspect(cont, inspect) != 0) { ERROR("Failed to transform to mount point"); @@ -1626,11 +1640,13 @@ out: static int container_rename_cb(const struct isulad_container_rename_request *request, struct isulad_container_rename_response **response) { + int nret = 0; uint32_t cc = ISULAD_SUCCESS; char *id = NULL; char *old_name = NULL; char *new_name = NULL; container_t *cont = NULL; + char annotations[EXTRA_ANNOTATION_MAX] = {0}; DAEMON_CLEAR_ERRMSG(); @@ -1670,7 +1686,14 @@ static int container_rename_cb(const struct isulad_container_rename_request *req goto pack_response; } + nret = snprintf(annotations, sizeof(annotations), "oldName=%s", request->old_name); + if (nret < 0 || (size_t)nret >= sizeof(annotations)) { + cc = ISULAD_ERR_EXEC; + goto pack_response; + } + EVENT("Event: {Object: %s, Type: Renamed to %s}", id, new_name); + (void)isulad_monitor_send_container_event(id, RENAME, -1, 0, NULL, annotations); goto pack_response; pack_response: diff --git a/src/services/execution/execute/execution_network.c b/src/services/execution/execute/execution_network.c index 8b25de9..d70d921 100644 --- a/src/services/execution/execute/execution_network.c +++ b/src/services/execution/execute/execution_network.c @@ -35,6 +35,7 @@ #include "containers_store.h" #include "namespace.h" #include "path.h" +#include "selinux_label.h" static int write_hostname_to_file(const char *rootfs, const char *hostname) { @@ -47,7 +48,7 @@ static int write_hostname_to_file(const char *rootfs, const char *hostname) goto error_out; } if (hostname != NULL) { - ret = util_write_file(file_path, hostname, strlen(hostname)); + ret = util_write_file(file_path, hostname, strlen(hostname), NETWORK_MOUNT_FILE_MODE); if (ret) { SYSERROR("Failed to write %s", file_path); isulad_set_error_message("Failed to write %s: %s", file_path, strerror(errno)); @@ -139,7 +140,7 @@ static int write_content_to_file(const char *file_path, const char *content) int ret = 0; if (content != NULL) { - ret = util_write_file(file_path, content, strlen(content)); + ret = util_write_file(file_path, content, strlen(content), NETWORK_MOUNT_FILE_MODE); if (ret != 0) { SYSERROR("Failed to write file %s", file_path); isulad_set_error_message("Failed to write file %s: %s", file_path, strerror(errno)); @@ -589,7 +590,7 @@ cleanup: return ret; } -static int merge_resolv(const host_config *host_spec, const char *rootfs) +static int merge_resolv(const host_config *host_spec, const char *rootfs, const char *resolv_conf_path) { int ret = 0; size_t length = 0; @@ -607,7 +608,7 @@ static int merge_resolv(const host_config *host_spec, const char *rootfs) ret = -1; goto error_out; } - ret = fopen_network(&fp, &file_path, rootfs, "/etc/resolv.conf"); + ret = fopen_network(&fp, &file_path, rootfs, resolv_conf_path); if (ret != 0) { goto error_out; } @@ -686,16 +687,35 @@ out: return ret; } -int merge_network(const host_config *host_spec, const char *rootfs, const char *hostname) +static int merge_network_for_universal_container(const host_config *host_spec, const char *runtime_root, const char *id) +{ + int ret = 0; + int nret = 0; + char root_path[PATH_MAX] = {0x00}; + + if (runtime_root == NULL || id == NULL) { + ERROR("empty runtime root or id"); + return -1; + } + + nret = snprintf(root_path, PATH_MAX, "%s/%s", runtime_root, id); + if (nret < 0 || nret >= PATH_MAX) { + ERROR("Failed to print string"); + return -1; + } + + ret = merge_resolv(host_spec, root_path, "/resolv.conf"); + if (ret) { + return -1; + } + + return 0; +} + +static int merge_network_for_syscontainer(const host_config *host_spec, const char *rootfs, const char *hostname) { int ret = 0; - if (host_spec == NULL) { - return -1; - } - if (!host_spec->system_container || rootfs == NULL) { - return 0; - } ret = write_hostname_to_file(rootfs, hostname); if (ret) { return -1; @@ -712,7 +732,7 @@ int merge_network(const host_config *host_spec, const char *rootfs, const char * if (ret) { return -1; } - ret = merge_resolv(host_spec, rootfs); + ret = merge_resolv(host_spec, rootfs, "/etc/resolv.conf"); if (ret) { return -1; } @@ -723,6 +743,24 @@ int merge_network(const host_config *host_spec, const char *rootfs, const char * return 0; } +int merge_network(const host_config *host_spec, const char *rootfs, const char *runtime_root, + const char *id, const char *hostname) +{ + int ret = 0; + + if (host_spec == NULL) { + return -1; + } + + if (!host_spec->system_container || rootfs == NULL) { + ret = merge_network_for_universal_container(host_spec, runtime_root, id); + } else { + ret = merge_network_for_syscontainer(host_spec, rootfs, hostname); + } + + return ret; +} + static container_t *get_networked_container(const char *id, const char *connected_id, bool check_state) { container_t *nc = NULL; @@ -831,7 +869,7 @@ static int create_default_hostname(const char *id, const char *rootpath, bool sh } - if (util_write_file(file_path, hostname_content, strlen(hostname_content)) != 0) { + if (util_write_file(file_path, hostname_content, strlen(hostname_content), NETWORK_MOUNT_FILE_MODE) != 0) { ERROR("Failed to create default hostname"); ret = -1; goto out; @@ -877,7 +915,7 @@ static int write_default_hosts(const char *file_path, const char *hostname) goto out_free; } - ret = util_write_file(file_path, content, strlen(content)); + ret = util_write_file(file_path, content, strlen(content), NETWORK_MOUNT_FILE_MODE); if (ret != 0) { ret = -1; goto out_free; @@ -903,7 +941,7 @@ static int create_default_hosts(const char *id, const char *rootpath, bool share } if (share_host && util_file_exists(ETC_HOSTS)) { - ret = util_copy_file(ETC_HOSTS, file_path); + ret = util_copy_file(ETC_HOSTS, file_path, NETWORK_MOUNT_FILE_MODE); } else { ret = write_default_hosts(file_path, v2_spec->config->hostname); } @@ -924,7 +962,7 @@ static int write_default_resolve(const char *file_path) { const char *default_ipv4_dns = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n";; - return util_write_file(file_path, default_ipv4_dns, strlen(default_ipv4_dns)); + return util_write_file(file_path, default_ipv4_dns, strlen(default_ipv4_dns), NETWORK_MOUNT_FILE_MODE); } static int create_default_resolv(const char *id, const char *rootpath, container_config_v2_common_config *v2_spec) @@ -940,7 +978,7 @@ static int create_default_resolv(const char *id, const char *rootpath, container } if (util_file_exists(RESOLV_CONF_PATH)) { - ret = util_copy_file(RESOLV_CONF_PATH, file_path); + ret = util_copy_file(RESOLV_CONF_PATH, file_path, NETWORK_MOUNT_FILE_MODE); } else { ret = write_default_resolve(file_path); } diff --git a/src/services/execution/execute/execution_network.h b/src/services/execution/execute/execution_network.h index d4f76ee..c9c2135 100644 --- a/src/services/execution/execute/execution_network.h +++ b/src/services/execution/execute/execution_network.h @@ -23,7 +23,8 @@ extern "C" { #endif -int merge_network(const host_config *host_spec, const char *rootfs, const char *hostname); +int merge_network(const host_config *host_spec, const char *rootfs, const char *runtime_root, + const char *id, const char *hostname); int container_initialize_networking(const container_t *cont); diff --git a/src/services/execution/execute/execution_stream.c b/src/services/execution/execute/execution_stream.c index b5004ad..cfa334b 100644 --- a/src/services/execution/execute/execution_stream.c +++ b/src/services/execution/execute/execution_stream.c @@ -45,6 +45,7 @@ #include "logger_json_file.h" #include "constants.h" #include "runtime.h" +#include "collector.h" static char *create_single_fifo(const char *statepath, const char *subpath, const char *stdflag) { @@ -248,7 +249,115 @@ out: return ret; } -int merge_exec_process_env(defs_process *spec, const container_config *container_spec, const char **env, size_t env_len) +static int do_append_process_exec_env(const char **default_env, defs_process *spec) +{ + int ret = 0; + size_t new_size = 0; + size_t old_size = 0; + size_t i = 0; + size_t j = 0; + char **temp = NULL; + char **default_kv = NULL; + char **custom_kv = NULL; + size_t default_env_len = util_array_len(default_env); + + if (default_env_len == 0) { + return 0; + } + + if (default_env_len > LIST_ENV_SIZE_MAX - spec->env_len) { + ERROR("The length of envionment variables is too long, the limit is %d", LIST_ENV_SIZE_MAX); + isulad_set_error_message("The length of envionment variables is too long, the limit is %d", LIST_ENV_SIZE_MAX); + ret = -1; + goto out; + } + new_size = (spec->env_len + default_env_len) * sizeof(char *); + old_size = spec->env_len * sizeof(char *); + ret = mem_realloc((void **)&temp, new_size, spec->env, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for envionment variables"); + ret = -1; + goto out; + } + + spec->env = temp; + for (i = 0; i < default_env_len; i++) { + bool found = false; + default_kv = util_string_split(default_env[i], '='); + if (default_kv == NULL) { + continue; + } + + for (j = 0; j < spec->env_len; j++) { + custom_kv = util_string_split(spec->env[i], '='); + if (custom_kv == NULL) { + continue; + } + if (strcmp(default_kv[0], custom_kv[0]) == 0) { + found = true; + } + util_free_array(custom_kv); + custom_kv = NULL; + if (found) { + break; + } + } + + if (!found) { + spec->env[spec->env_len] = util_strdup_s(default_env[i]); + spec->env_len++; + } + util_free_array(default_kv); + default_kv = NULL; + } +out: + return ret; +} + +static int append_necessary_process_env(bool tty, const container_config *container_spec, defs_process *spec) +{ + int ret = 0; + int nret = 0; + char **default_env = NULL; + char host_name_str[MAX_HOST_NAME_LEN + 10] = { 0 }; + + if (util_array_append(&default_env, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin") != 0) { + ERROR("Failed to append default exec env"); + ret = -1; + goto out; + } + + if (container_spec->hostname != NULL) { + nret = snprintf(host_name_str, sizeof(host_name_str), "HOSTNAME=%s", container_spec->hostname); + if (nret < 0 || (size_t)nret >= sizeof(host_name_str)) { + ERROR("hostname is too long"); + ret = -1; + goto out; + } + if (util_array_append(&default_env, host_name_str) != 0) { + ERROR("Failed to append default exec env"); + ret = -1; + goto out; + } + } + + if (tty) { + if (util_array_append(&default_env, "TERM=xterm") != 0) { + ERROR("Failed to append default exec env"); + ret = -1; + goto out; + } + } + + ret = do_append_process_exec_env((const char **)default_env, spec); + +out: + util_free_array(default_env); + return ret; +} + +static int merge_exec_process_env(defs_process *spec, const container_config *container_spec, const char **env, + size_t env_len) { int ret = 0; size_t env_count = 0; @@ -340,6 +449,12 @@ static defs_process *make_exec_process_spec(const container_config *container_sp goto err_out; } + ret = append_necessary_process_env(request->tty, container_spec, spec); + if (ret != 0) { + ERROR("Failed to append necessary for exec process spec"); + goto err_out; + } + ret = dup_array_of_strings((const char **)request->argv, request->argv_len, &(spec->args), &(spec->args_len)); if (ret != 0) { ERROR("Failed to dup envs for exec process spec"); @@ -405,6 +520,7 @@ static int exec_container(container_t *cont, const char *runtime, char * const c params.rootpath = cont->root_path; params.timeout = request->timeout; params.suffix = request->suffix; + params.state = cont->state_path; params.spec = process_spec; if (runtime_exec(cont->common_config->id, runtime, ¶ms, exit_code)) { @@ -546,6 +662,51 @@ static int get_exec_user_info(const container_t *cont, const char *username, def out: return ret; } +static void get_exec_command(const container_config *conf, const container_exec_request *request, + char *exec_command, size_t len) +{ + size_t i; + bool should_abbreviated = false; + size_t start = 0; + size_t end = 0; + + for (i = 0; i < conf->entrypoint_len; i++) { + if (strlen(conf->entrypoint[i]) < len - strlen(exec_command)) { + (void)strcat(exec_command, conf->entrypoint[i]); + (void)strcat(exec_command, " "); + } else { + should_abbreviated = true; + goto out; + } + } + + for (i = 0; i < request->argv_len; i++) { + if (strlen(request->argv[i]) < len - strlen(exec_command)) { + (void)strcat(exec_command, request->argv[i]); + if (i != request->argv_len) { + (void)strcat(exec_command, " "); + } + } else { + should_abbreviated = true; + goto out; + } + } + +out: + if (should_abbreviated) { + if (strlen(exec_command) <= len - 1 - 3) { + start = strlen(exec_command); + end = start + 3; + } else { + start = len - 1 - 3; + end = len - 1; + } + + for (i = start; i < end; i++) { + exec_command[i] = '.'; + } + } +} static int container_exec_cb(const container_exec_request *request, container_exec_response **response, int stdinfd, struct io_write_wrapper *stdout_handler) @@ -559,6 +720,7 @@ static int container_exec_cb(const container_exec_request *request, container_ex pthread_t thread_id = 0; container_t *cont = NULL; defs_process_user *puser = NULL; + char exec_command[ARGS_MAX] = {0x00}; DAEMON_CLEAR_ERRMSG(); if (request == NULL || response == NULL) { @@ -574,6 +736,9 @@ static int container_exec_cb(const container_exec_request *request, container_ex set_log_prefix(id); EVENT("Event: {Object: %s, Type: execing}", id); + get_exec_command(cont->common_config->config, request, exec_command, sizeof(exec_command)); + (void)isulad_monitor_send_container_event(id, EXEC_CREATE, -1, 0, exec_command, NULL); + if (gc_is_gc_progress(id)) { isulad_set_error_message("You cannot exec container %s in garbage collector progress.", id); ERROR("You cannot exec container %s in garbage collector progress.", id); @@ -607,19 +772,27 @@ static int container_exec_cb(const container_exec_request *request, container_ex cc = ISULAD_ERR_EXEC; goto pack_response; } + } else { + if (cont->common_config->config->user != NULL) { + if (get_exec_user_info(cont, cont->common_config->config->user, &puser) != 0) { + cc = ISULAD_ERR_EXEC; + goto pack_response; + } + } } if (exec_prepare_console(cont, request, stdinfd, stdout_handler, fifos, &fifopath, &sync_fd, &thread_id)) { cc = ISULAD_ERR_EXEC; goto pack_response; } - + (void)isulad_monitor_send_container_event(id, EXEC_START, -1, 0, exec_command, NULL); if (exec_container(cont, cont->runtime, (char * const *)fifos, puser, request, &exit_code)) { cc = ISULAD_ERR_EXEC; goto pack_response; } EVENT("Event: {Object: %s, Type: execed}", id); + (void)isulad_monitor_send_container_event(id, EXEC_DIE, -1, 0, NULL, NULL); pack_response: container_exec_cb_end(*response, cc, exit_code, sync_fd, thread_id); @@ -780,6 +953,8 @@ static int container_attach_cb(const container_attach_request *request, containe params.stdout = fifos[1]; params.stderr = fifos[2]; + (void)isulad_monitor_send_container_event(id, ATTACH, -1, 0, NULL, NULL); + if (runtime_attach(cont->common_config->id, cont->runtime, ¶ms)) { ERROR("Runtime attach container failed"); cc = ISULAD_ERR_EXEC; @@ -1055,7 +1230,7 @@ static int pause_container(const container_t *cont) const char *id = cont->common_config->id; params.rootpath = cont->root_path; - + params.state = cont->state_path; if (runtime_pause(id, cont->runtime, ¶ms)) { ERROR("Failed to pause container:%s", id); ret = -1; @@ -1081,7 +1256,7 @@ static int resume_container(const container_t *cont) const char *id = cont->common_config->id; params.rootpath = cont->root_path; - + params.state = cont->state_path; if (runtime_resume(id, cont->runtime, ¶ms)) { ERROR("Failed to resume container:%s", id); ret = -1; @@ -1163,6 +1338,7 @@ static int copy_from_container_cb(const struct isulad_copy_from_container_reques goto cleanup_rootfs; } + (void)isulad_monitor_send_container_event(cont->common_config->id, ARCHIVE_PATH, -1, 0, NULL, NULL); ret = 0; cleanup_rootfs: if (im_umount_container_rootfs(cont->common_config->image_type, cont->common_config->image, @@ -1454,6 +1630,7 @@ static int copy_to_container_cb(const container_copy_to_request *request, goto cleanup_rootfs; } + (void)isulad_monitor_send_container_event(cont->common_config->id, EXTRACT_TO_DIR, -1, 0, NULL, NULL); ret = 0; cleanup_rootfs: diff --git a/src/services/execution/manager/container_unix.c b/src/services/execution/manager/container_unix.c index 12035f8..11d4c04 100644 --- a/src/services/execution/manager/container_unix.c +++ b/src/services/execution/manager/container_unix.c @@ -78,10 +78,8 @@ container_t *container_new(const char *runtime, const char *rootpath, const char cont = util_common_calloc_s(sizeof(container_t)); if (cont == NULL) { - free_container_config_v2_common_config(tmp_common_config); - free_host_config(tmp_host_config); ERROR("Out of memory"); - return NULL; + goto error_out; } atomic_int_set(&cont->refcnt, 1); @@ -124,6 +122,12 @@ container_t *container_new(const char *runtime, const char *rootpath, const char return cont; error_out: + if (cont != NULL) { + *common_config = cont->common_config; + *hostconfig = cont->hostconfig; + cont->common_config = NULL; + cont->hostconfig = NULL; + } container_unref(cont); return NULL; } @@ -1054,4 +1058,46 @@ out: return ret; } +/* + * @cont: check container + * @mpath: target mount path + * */ +bool has_mount_for(container_t *cont, const char *mpath) +{ + size_t i = 0; + char *work = NULL; + + if (cont == NULL || mpath == NULL) { + return false; + } + + if (cont->common_config == NULL) { + return false; + } + + if (cont->common_config->mount_points == NULL) { + return false; + } + + for (; i < cont->common_config->mount_points->len; i++) { + if (strcmp(cont->common_config->mount_points->keys[i], mpath) == 0) { + return true; + } + } + + if (cont->hostconfig == NULL) { + return false; + } + for (i = 0; i < cont->hostconfig->binds_len; i++) { + work = strrchr(cont->hostconfig->binds[i], ':'); + if (work == NULL) { + continue; + } + if (strcmp(work, mpath) == 0) { + return true; + } + } + + return false; +} diff --git a/src/services/execution/manager/container_unix.h b/src/services/execution/manager/container_unix.h index 1f7f950..c509373 100644 --- a/src/services/execution/manager/container_unix.h +++ b/src/services/execution/manager/container_unix.h @@ -108,6 +108,8 @@ int save_config_v2_json(const char *id, const char *rootpath, const char *v2conf int container_read_proc(uint32_t pid, container_pid_t *pid_info); +bool has_mount_for(container_t *cont, const char *mpath); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/src/services/execution/manager/health_check.c b/src/services/execution/manager/health_check.c index ed05b83..8f006a5 100644 --- a/src/services/execution/manager/health_check.c +++ b/src/services/execution/manager/health_check.c @@ -559,7 +559,7 @@ void *health_check_run(void *arg) container_req->tty = false; container_req->attach_stdin = false; container_req->attach_stdout = true; - container_req->attach_stderr = true; + container_req->attach_stderr = false; container_req->timeout = timeout_with_default(config->health_check->timeout, DEFAULT_PROBE_TIMEOUT) / Time_Second; container_req->container_id = util_strdup_s(cont->common_config->id); container_req->argv = cmd_slice; diff --git a/src/services/execution/manager/monitord.h b/src/services/execution/manager/monitord.h index 92401be..334e1fa 100644 --- a/src/services/execution/manager/monitord.h +++ b/src/services/execution/manager/monitord.h @@ -18,16 +18,23 @@ #include #include #include "engine.h" +#include "libisulad.h" + +#define ARGS_MAX 255 /* # args chars in a monitord msg */ +#define EXTRA_ANNOTATION_MAX 1024 /* # annotation chars in a monitord msg */ typedef enum { - monitord_msg_state, - monitord_msg_priority, - monitord_msg_exit_code + MONITORD_MSG_STATE, + MONITORD_MSG_PRIORITY, + MONITORD_MSG_EXIT_CODE } msg_type_t; struct monitord_msg { msg_type_t type; + msg_event_type_t event_type; char name[NAME_MAX + 1]; + char args[ARGS_MAX]; + char extra_annations[EXTRA_ANNOTATION_MAX]; int value; int exit_code; int pid; diff --git a/src/services/execution/manager/restore.c b/src/services/execution/manager/restore.c index 6f6287c..cdd1c5b 100644 --- a/src/services/execution/manager/restore.c +++ b/src/services/execution/manager/restore.c @@ -309,6 +309,7 @@ static int restore_state(container_t *cont) #endif params.rootpath = cont->root_path; + params.state = cont->state_path; nret = runtime_status(id, runtime, ¶ms, &real_status); if (nret != 0) { ERROR("Failed to restore container %s, make real status to STOPPED. Due to can not load container with status %d", id, diff --git a/src/services/execution/manager/supervisor.c b/src/services/execution/manager/supervisor.c index 2440abe..7f07c70 100644 --- a/src/services/execution/manager/supervisor.c +++ b/src/services/execution/manager/supervisor.c @@ -187,7 +187,7 @@ retry: } } - (void)isulad_monitor_send_event(name, STOPPED, (int)pid, data->exit_code); + (void)isulad_monitor_send_container_event(name, STOPPED, (int)pid, data->exit_code, NULL, NULL); supervisor_handler_data_free(data); diff --git a/src/services/execution/spec/selinux_label.c b/src/services/execution/spec/selinux_label.c new file mode 100644 index 0000000..54b1ab0 --- /dev/null +++ b/src/services/execution/spec/selinux_label.c @@ -0,0 +1,1076 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2019-12-15 + * Description: provide selinux label handle function definition + ******************************************************************************/ + +#include "selinux_label.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "map.h" +#include "log.h" +#include "utils.h" +#include "namespace.h" +#include "libisulad.h" +#include "read_file.h" + +#define SELINUXFS_MOUNT "/sys/fs/selinux" +#define SELINUXFS_MAGIC 0xf97cff8c + +typedef struct selinux_state_t { + bool enabled_set; + bool enabled; + bool selinuxf_set; + char *selinuxfs; + map_t *mcs_list; // map string boolean + pthread_rwlock_t rwlock; +} selinux_state; + +static selinux_state *g_selinux_state = NULL; + +static bool set_state_enable(bool enabled) +{ + bool result = false; + + if (pthread_rwlock_rdlock(&g_selinux_state->rwlock) != 0) { + ERROR("lock mcs list failed"); + return false; + } + + g_selinux_state->enabled_set = true; + g_selinux_state->enabled = enabled; + result = g_selinux_state->enabled; + + if (pthread_rwlock_unlock(&g_selinux_state->rwlock) != 0) { + ERROR("unlock mcs list failed"); + } + + return result; +} + +static int set_state_selinux_fs(char *selinuxfs) +{ + if (pthread_rwlock_rdlock(&g_selinux_state->rwlock) != 0) { + ERROR("lock selinux state failed"); + return -1; + } + + g_selinux_state->selinuxf_set = true; + free(g_selinux_state->selinuxfs); + g_selinux_state->selinuxfs = util_strdup_s(selinuxfs); + + if (pthread_rwlock_unlock(&g_selinux_state->rwlock) != 0) { + ERROR("unlock selinux state failed"); + return -1; + } + + return 0; +} + +/* Verify the mount point for selinux file system has a selinuxfs. */ +static bool verify_selinuxfs_mount(const char *mnt) +{ + struct statfs sfbuf; + + while (true) { + int rc = statfs(mnt, &sfbuf); + if (rc == 0) { + break; + } + if (errno == EINTR) { + continue; + } + return false; + } + + if ((uint32_t)sfbuf.f_type != (uint32_t)SELINUXFS_MAGIC) { + return false; + } + + if ((sfbuf.f_flags & ST_RDONLY) != 0) { + return false; + } + + return true; +} +// returns a next selinuxfs mount point found, +// if there is one, or an empty string in case of EOF or error. +static void find_selinux_fs_among_mounts(char **fs) +{ +#define MOUNT_POOINT_FIFTH_FIELD 5 + FILE *fp = NULL; + char *buf = NULL; + char **fields = NULL; + size_t len; + ssize_t num; + + fp = fopen("/proc/self/mountinfo", "re"); + if (fp == NULL) { + INFO("/proc/self/mountinfo not exists"); + return; + } + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + num = getline(&buf, &len, fp); + while (num != -1) { + if (!strstr(buf, " - selinuxfs ")) { + num = getline(&buf, &len, fp); + continue; + } + fields = util_string_split((const char *)buf, ' '); + if (fields == NULL || util_array_len((const char **)fields) < MOUNT_POOINT_FIFTH_FIELD + 1) { + util_free_array(fields); + num = getline(&buf, &len, fp); + continue; + } + if (verify_selinuxfs_mount(fields[MOUNT_POOINT_FIFTH_FIELD - 1])) { + *fs = util_strdup_s(fields[MOUNT_POOINT_FIFTH_FIELD - 1]); + } + goto out; + } + +out: + util_free_array(fields); + free(buf); + fclose(fp); +} + +static void find_selinux_fs(char **fs) +{ + // fast path: check the default mount first + if (verify_selinuxfs_mount(SELINUXFS_MOUNT)) { + *fs = util_strdup_s(SELINUXFS_MOUNT); + return; + } + // check if selinuxfs is available before going the slow path + if (selinuxfs_exists() == 0) { + return; + } + // slow path: try to find among the mounts + find_selinux_fs_among_mounts(fs); + + return; +} + +static int get_state_selinuxfs(char **fs) +{ + bool selinuxfs_set = false; + char *selinuxfs = NULL; + + if (pthread_rwlock_rdlock(&g_selinux_state->rwlock) != 0) { + ERROR("lock mcs list failed"); + return -1; + } + + selinuxfs_set = g_selinux_state->selinuxf_set; + selinuxfs = g_selinux_state->selinuxfs; + + if (pthread_rwlock_unlock(&g_selinux_state->rwlock) != 0) { + ERROR("unlock mcs list failed"); + return -1; + } + + if (selinuxfs_set) { + *fs = util_strdup_s(selinuxfs); + return 0; + } + + find_selinux_fs(fs); + + return set_state_selinux_fs(*fs); +} + +static int get_selinux_mount_point(char **fs) +{ + return get_state_selinuxfs(fs); +} + +static int read_con(const char *fpath, char **content) +{ + int ret = 0; + size_t file_size = 0; + char *tmp = NULL; + char *trim_str = NULL; + + if (fpath == NULL) { + ERROR("Empty path"); + return -1; + } + + tmp = read_file(fpath, &file_size); + if (tmp == NULL) { + ERROR("Failed to read file: %s", fpath); + ret = -1; + goto out; + } + + trim_str = util_trim_space(tmp); + *content = util_strdup_s(trim_str); + +out: + free(tmp); + return ret; +} + +// get_current_label returns the SELinux label of the current process thread. +static int get_current_label(char **content) +{ + int nret = 0; + char path[PATH_MAX] = {0}; + + nret = snprintf(path, sizeof(path), "/proc/self/task/%ld/attr/current", + (long int)syscall(__NR_gettid)); + if (nret < 0 || nret >= sizeof(path)) { + ERROR("Humanize sprintf failed!"); + return -1; + } + + return read_con(path, content); +} + +bool selinux_get_enable() +{ + bool enabled_set = false; + bool enabled = false; + char *fs = NULL; + + if (pthread_rwlock_rdlock(&g_selinux_state->rwlock) != 0) { + ERROR("lock selinux state failed"); + return false; + } + + enabled_set = g_selinux_state->enabled_set; + enabled = g_selinux_state->enabled; + + if (pthread_rwlock_unlock(&g_selinux_state->rwlock) != 0) { + ERROR("unlock selinux state failed"); + return false; + } + + if (enabled_set) { + return enabled; + } + + enabled = false; + + if (get_selinux_mount_point(&fs) != 0) { + ERROR("Failed to get selinux mount point"); + return false; + } + + if (fs != NULL) { + char *content = NULL; + + if (get_current_label(&content) != 0 || content == NULL) { + ERROR("Failed to get current label"); + return false; + } + if (strcmp(content, "kernel") != 0) { + enabled = true; + } + free(content); + } + + free(fs); + return set_state_enable(enabled); +} + +// just disable selinux support for iSulad +void selinux_set_disabled() +{ + (void)set_state_enable(false); +} + +static int get_random_value(unsigned int range, unsigned int *val) +{ + int ret = 0; + int num = 0; + int fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) { + ERROR("Failed to open urandom device\n"); + return -1; + } + + if (read(fd, &num, sizeof(int)) < 0) { + ERROR("Failed to read urandom value\n"); + ret = -1; + goto out; + } + + *val = (unsigned)num % range; + +out: + close(fd); + return ret; +} + +/* selinux state free */ +static void selinux_state_free(selinux_state *state) +{ + if (state == NULL) { + return; + } + + map_free(state->mcs_list); + state->mcs_list = NULL; + free(state->selinuxfs); + pthread_rwlock_destroy(&(state->rwlock)); + free(state); +} + +/* memory store new */ +static selinux_state *selinux_state_new(void) +{ + selinux_state *state = util_common_calloc_s(sizeof(selinux_state)); + if (state == NULL) { + ERROR("Out of memory"); + return NULL; + } + + if (pthread_rwlock_init(&(state->rwlock), NULL) != 0) { + ERROR("Failed to init memory store rwlock"); + free(state); + return NULL; + } + + state->mcs_list = map_new(MAP_STR_BOOL, MAP_DEFAULT_CMP_FUNC, MAP_DEFAULT_FREE_FUNC); + if (state->mcs_list == NULL) { + ERROR("Out of memory"); + goto error_out; + } + + return state; + +error_out: + selinux_state_free(g_selinux_state); + return NULL; +} + +/* selinux state init */ +int selinux_state_init(void) +{ + g_selinux_state = selinux_state_new(); + if (g_selinux_state == NULL) { + return -1; + } + + return 0; +} + +/* MCS already exists */ +static bool is_mcs_already_exists(const char *mcs) +{ + char *val = NULL; + + if (mcs == NULL) { + return false; + } + if (pthread_rwlock_rdlock(&g_selinux_state->rwlock) != 0) { + ERROR("lock selinux state failed"); + return false; + } + + val = map_search(g_selinux_state->mcs_list, (void *)mcs); + + if (pthread_rwlock_unlock(&g_selinux_state->rwlock) != 0) { + ERROR("unlock selinux state failed"); + } + + return val != NULL; +} + +/* MCS list add */ +static bool mcs_add(const char *mcs) +{ + bool ret = false; + bool val = true; + + if (pthread_rwlock_wrlock(&g_selinux_state->rwlock)) { + ERROR("lock memory store failed"); + return false; + } + + ret = map_replace(g_selinux_state->mcs_list, (void *)mcs, (void *)&val); + + if (pthread_rwlock_unlock(&g_selinux_state->rwlock)) { + ERROR("unlock memory store failed"); + return false; + } + + return ret; +} + +static bool mcs_delete(const char *mcs) +{ + bool ret = false; + bool val = true; + + if (mcs == NULL) { + return 0; + } + + if (pthread_rwlock_wrlock(&g_selinux_state->rwlock) != 0) { + ERROR("lock name index failed"); + return false; + } + + ret = map_replace(g_selinux_state->mcs_list, (void *)mcs, (void *)&val); + + if (pthread_rwlock_unlock(&g_selinux_state->rwlock) != 0) { + ERROR("unlock name index failed"); + return false; + } + + return ret; +} + +static int add_mcs_to_global_list(const char *mcs) +{ + if (is_mcs_already_exists(mcs)) { + DEBUG("MCS label already exists"); + return -1; + } + + if (!mcs_add(mcs)) { + ERROR("Failed to add mcs to global list"); + return -1; + } + + return 0; +} + +static int uniq_mcs(unsigned int range, char *mcs, size_t len) +{ + unsigned int c1, c2; + + while (true) { + int nret; + + if (get_random_value(range, &c1) != 0 || get_random_value(range, &c2) != 0) { + return -1; + } + if (c1 == c2) { + continue; + } else if (c1 > c2) { + unsigned int tmp = c1; + c1 = c2; + c2 = tmp; + } + + nret = snprintf(mcs, len, "s0:c%d,c%d", c1, c2); + if (nret < 0 || nret >= len) { + ERROR("Failed to compose mcs"); + return -1; + } + + if (add_mcs_to_global_list(mcs)) { + continue; + } + + break; + } + + return 0; +} + +static bool should_skip_in_lxc_contexts(const char *line) +{ + // skip blank lines + if (strlen(line) == 0) { + return true; + } + + // skip comments + if (line[0] == ';' || line[0] == '#') { + return true; + } + + return false; +} + +static int parse_lxc_context_info(const char *line, char **process_label, char **file_label) +{ + int ret = 0; + size_t groups_len = 0; + char **groups = NULL; + char *key = NULL; + char *val = NULL; + + groups = util_string_split(line, '='); + if (groups == NULL) { + ERROR("Out of memory"); + return -1; + } + + groups_len = util_array_len((const char **)groups); + if (groups_len != 2) { + ERROR("Invalid context"); + ret = -1; + goto out; + } + + key = util_trim_space(groups[0]); + val = util_trim_space(groups[1]); + + if (strcmp(key, "process") == 0) { + free(*process_label); + *process_label = util_string_delchar(val, '"'); + } else if (strcmp(key, "file") == 0) { + free(*file_label); + *file_label = util_string_delchar(val, '"'); + } + +out: + util_free_array(groups); + return ret; +} + +static void update_process_and_mount_label_range(char **process_label, char **file_label) +{ +#define MCS_MAX_LEN 20 + context_t scon = context_new(*process_label); + + if (context_range_get(scon) != NULL) { + char mcs[MCS_MAX_LEN] = { 0x00 }; + + uniq_mcs(1024, mcs, MCS_MAX_LEN); + context_range_set(scon, mcs); + free(*process_label); + *process_label = util_strdup_s(context_str(scon)); + + context_t mcon = context_new(*file_label); + context_range_set(mcon, mcs); + free(*file_label); + *file_label = util_strdup_s(context_str(mcon)); + context_free(mcon); + } + + context_free(scon); +} + +static int container_label(char **process_label, char **file_label) +{ + int ret = 0; + size_t len; + ssize_t num; + FILE *file = NULL; + char *buf = NULL; + const char *lxc_path = NULL; + + if (!selinux_get_enable()) { + return 0; + } + + lxc_path = selinux_lxc_contexts_path(); + if (lxc_path == NULL) { + ERROR("Failed to get selinux lxc contexts path"); + return -1; + } + + file = fopen(lxc_path, "re"); + if (file == NULL) { + ERROR("Failed to open '%s'", lxc_path); + return -1; + } + __fsetlocking(file, FSETLOCKING_BYCALLER); + + for (num = getline(&buf, &len, file); num != -1; num = getline(&buf, &len, file)) { + char *line = util_strdup_s(buf); + char *tmp_line = util_trim_space(line); + + if (should_skip_in_lxc_contexts(tmp_line)) { + free(line); + continue; + } + + if (parse_lxc_context_info(tmp_line, process_label, file_label) != 0) { + ERROR("Failed to parse lxc context info"); + free(line); + ret = -1; + goto out; + } + + free(line); + } + + if (*process_label == NULL || *file_label == NULL) { + ret = 0; + goto out; + } + + update_process_and_mount_label_range(process_label, file_label); + +out: + free(buf); + fclose(file); + return ret; +} + +static bool valid_options(const char *opt) +{ + size_t i; + const char *opts[] = { "disable", "type", "user", "role", "level" }; + + for (i = 0; i < sizeof(opts) / sizeof(char *); i++) { + if (strcmp(opt, opts[i]) == 0) { + return true; + } + } + + return false; +} + +static int release_label(const char *label) +{ + int ret = 0; + const char *range = NULL; + + if (label == NULL) { + ERROR("Invalid label"); + return -1; + } + + context_t tmp = context_new(label); + range = context_range_get(tmp); + if (range != NULL) { + if (!mcs_delete(range)) { + ERROR("delete mcs '%s' failed", range); + ret = -1; + goto out; + } + } + +out: + context_free(tmp); + return ret; +} + +static int reserve_label(const char *label) +{ + int ret = 0; + const char *range = NULL; + + if (label == NULL) { + ERROR("Invalid label"); + return -1; + } + + context_t tmp = context_new(label); + range = context_range_get(tmp); + if (range != NULL) { + if (!mcs_add(range)) { + ERROR("add mcs '%s' failed", range); + ret = -1; + goto out; + } + } + +out: + context_free(tmp); + return ret; +} + +static int parse_label_security_opt(const char *label_opt, context_t pcon, context_t mcon) +{ + int ret = 0; + bool failure = false; + char **items = NULL; + size_t items_len = 0; + + items = util_string_split_n(label_opt, ':', 2); + if (items == NULL) { + ERROR("split label '%s' failed", label_opt); + ret = -1; + goto out; + } + + items_len = util_array_len((const char **)items); + if (items_len != 2 || strlen(items[1]) == 0) { + isulad_set_error_message("Bad security label option \"%s\"", label_opt); + ERROR("Bad security label option \"%s\"", label_opt); + ret = -1; + goto out; + } + + if (!valid_options(items[0])) { + isulad_set_error_message("Bad label option \"%s\", valid options 'disable, user, role, level, type'", items[0]); + ERROR("Bad label option \"%s\", valid options 'disable, user, role, level, type'", items[0]); + ret = -1; + goto out; + } + + if (strcmp(items[0], "type") == 0) { + failure = (context_type_set(pcon, items[1]) != 0); + } else if (strcmp(items[0], "user") == 0) { + failure = (context_user_set(pcon, items[1]) != 0 || context_user_set(mcon, items[1]) != 0); + } else if (strcmp(items[0], "role") == 0) { + failure = (context_role_set(pcon, items[1]) != 0); + } else if (strcmp(items[0], "level") == 0) { + failure = (context_range_set(pcon, items[1]) != 0 || context_range_set(mcon, items[1]) != 0); + } else { + failure = true; + } + + if (failure) { + isulad_set_error_message("Failed to set selinux context: %s", label_opt); + ERROR("Failed to set selinux context: %s", label_opt); + ret = -1; + goto out; + } + +out: + util_free_array(items); + return ret; +} + +// InitLabels returns the process label and file labels to be used within +// the container. A list of options can be passed into this function to alter +// the labels. The labels returned will include a random MCS String, that is +// guaranteed to be unique. +int init_label(const char **label_opts, size_t label_opts_len, char **dst_process_label, char **dst_mount_label) +{ + int ret = 0; + char *process_label = NULL; + char *mount_label = NULL; + context_t pcon = NULL; + context_t mcon = NULL; + + if (!selinux_get_enable()) { + return 0; + } + + if (container_label(&process_label, &mount_label) != 0) { + ret = -1; + goto out; + } + + if (process_label != NULL) { + size_t i; + pcon = context_new(process_label); + mcon = context_new(mount_label); + for (i = 0; i < label_opts_len; i++) { + if (strcmp(label_opts[i], "disable") == 0) { + goto out; + } + if (strstr(label_opts[i], ":") == NULL) { + isulad_set_error_message("Bad label option %s, valid options 'disable" + " or user, role, level, type' followed by ':' and a value", + label_opts[i]); + ERROR("Bad label option %s, valid options 'disable' or \n" + "'user, role, level, type' followed by ':' and a value", + label_opts[i]); + ret = -1; + goto out; + } + + if (parse_label_security_opt(label_opts[i], pcon, mcon) != 0) { + ERROR("Failed to parse security label option"); + ret = -1; + goto out; + } + } + if (release_label(process_label) != 0) { + ERROR("Failed to release process label", process_label); + ret = -1; + goto out; + } + free(process_label); + process_label = util_strdup_s(context_str(pcon)); + free(mount_label); + mount_label = util_strdup_s(context_str(mcon)); + if (reserve_label(process_label) != 0) { + ERROR("Failed to release process label", process_label); + ret = -1; + goto out; + } + } + + *dst_process_label = process_label; + *dst_mount_label = mount_label; + process_label = NULL; + mount_label = NULL; + +out: + context_free(pcon); + context_free(mcon); + free(process_label); + free(mount_label); + return ret; +} + +static bool is_exclude_relabel_path(const char *path) +{ + const char *exclude_path[] = { "/", "/usr", "/etc", "/tmp", "/home", "/run", "/var", "/root" }; + size_t i; + + for (i = 0; i < sizeof(exclude_path) / sizeof(char *); i++) { + if (strcmp(path, exclude_path[i]) == 0) { + return true; + } + } + + return false; +} + +// Prevent users from relabing system files +static int bad_prefix(const char *fpath) +{ + const char *bad_prefixes = "/usr"; + + if (fpath == NULL) { + ERROR("Empty file path"); + return -1; + } + + if (strncmp(fpath, bad_prefixes, strlen(bad_prefixes)) == 0) { + ERROR("relabeling content in %s is not allowed", bad_prefixes); + return -1; + } + + return 0; +} + +static int recurse_set_file_label(const char *basePath, const char *label) +{ + int ret = 0; + DIR *dir = NULL; + struct dirent *ptr = NULL; + char base[PATH_MAX] = {0}; + + if ((dir = opendir(basePath)) == NULL) { + ERROR("Failed to Open dir: %s", basePath); + return -1; + } + + ret = lsetfilecon(basePath, label); + if (ret != 0) { + ERROR("Failed to set file label"); + goto out; + } + + while ((ptr = readdir(dir)) != NULL) { + if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) { + continue; + } else { + int nret = snprintf(base, sizeof(base), "%s/%s", basePath, ptr->d_name); + if (nret < 0 || nret >= sizeof(base)) { + ERROR("Failed to get path"); + ret = -1; + goto out; + } + if (ptr->d_type == DT_DIR) { + ret = recurse_set_file_label(base, label); + if (ret != 0) { + ERROR("Failed to set dir label"); + goto out; + } + } else { + ret = lsetfilecon(base, label); + if (ret != 0) { + ERROR("Failed to set file label"); + goto out; + } + } + } + } + +out: + closedir(dir); + return ret; +} + +// Chcon changes the `fpath` file object to the SELinux label `label`. +// If `fpath` is a directory and `recurse`` is true, Chcon will walk the +// directory tree setting the label. +static int selinux_chcon(const char *fpath, const char *label, bool recurse) +{ + struct stat s_buf; + + if (fpath == NULL) { + ERROR("Empty file path"); + return -1; + } + + if (label == NULL) { + return 0; + } + + if (bad_prefix(fpath) != 0) { + return -1; + } + if (stat(fpath, &s_buf) != 0) { + return -1; + } + if (recurse && S_ISDIR(s_buf.st_mode)) { + return recurse_set_file_label(fpath, label); + } + + if (lsetfilecon(fpath, label) != 0) { + ERROR("Failed to set file label"); + return -1; + } + + return 0; +} + +// Relabel changes the label of path to the filelabel string. +// It changes the MCS label to s0 if shared is true. +// This will allow all containers to share the content. +int relabel(const char *path, const char *file_label, bool shared) +{ + int ret = 0; + char *tmp_file_label = NULL; + + if (!selinux_get_enable()) { + return 0; + } + + if (file_label == NULL) { + return 0; + } + + tmp_file_label = util_strdup_s(file_label); + if (is_exclude_relabel_path(path)) { + ERROR("SELinux relabeling of %s is not allowed", path); + ret = -1; + goto out; + } + + if (shared) { + context_t c = context_new(file_label); + context_range_set(c, "s0"); + free(tmp_file_label); + tmp_file_label = util_strdup_s(context_str(c)); + context_free(c); + } + + if (selinux_chcon(path, tmp_file_label, true) != 0) { + ERROR("Failed to modify %s's selinux context: %s", path, tmp_file_label); + ret = -1; + goto out; + } + +out: + free(tmp_file_label); + return ret; +} + +static int append_security_opt_string(const char *field, const char *value, char ***security_opts) +{ + int ret = 0; + int nret = 0; + char *sec_opt = NULL; + size_t temp_len = strlen(field) + strlen(value) + 1; + + sec_opt = util_common_calloc_s(temp_len); + if (sec_opt == NULL) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + nret = snprintf(sec_opt, temp_len, "%s%s", field, value); + if (nret < 0 || nret >= temp_len) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + if (util_array_append(security_opts, sec_opt) < 0) { + ERROR("Failed to append element to array"); + ret = -1; + goto out; + } + +out: + free(sec_opt); + return ret; +} + +// DupSecOpt takes an SELinux process label and returns security options that +// can be used to set the SELinux Type and Level for future container processes. +int dup_security_opt(const char *src, char ***dst, size_t *len) +{ + int ret = 0; + size_t new_len = 3; + char **security_opts = NULL; + + if (src == NULL) { + return 0; + } + + context_t con = context_new(src); + if (context_user_get(con) == NULL || context_role_get(con) == NULL || context_type_get(con) == NULL) { + return 0; + } + if (context_range_get(con) != NULL) { + new_len++; + } + + if (append_security_opt_string("user:", context_user_get(con), &security_opts) != 0) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + if (append_security_opt_string("role:", context_role_get(con), &security_opts) != 0) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + if (append_security_opt_string("type:", context_type_get(con), &security_opts) != 0) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + + if (context_range_get(con) != NULL) { + if (append_security_opt_string("level:", context_range_get(con), &security_opts) != 0) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + } + *dst = security_opts; + *len = new_len; + + security_opts = NULL; + +out: + util_free_array(security_opts); + context_free(con); + return ret; +} + +int get_disable_security_opt(char ***labels, size_t *labels_len) +{ + if (util_array_append(labels, "disable") != 0) { + ERROR("Failed to append label"); + return -1; + } + + *labels_len = util_array_len((const char **)(*labels)); + + return 0; +} diff --git a/src/services/execution/spec/selinux_label.h b/src/services/execution/spec/selinux_label.h new file mode 100644 index 0000000..737e099 --- /dev/null +++ b/src/services/execution/spec/selinux_label.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2019-12-15 + * Description: provide selinux label handle function definition + ******************************************************************************/ + +#ifndef __SELINUX_LABLE_H +#define __SELINUX_LABLE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int selinux_state_init(void); +void selinux_set_disabled(); +bool selinux_get_enable(); +int init_label(const char **label_opts, size_t label_opts_len, char **process_label, char **mount_label); +int relabel(const char *path, const char *file_label, bool shared); +int get_disable_security_opt(char ***labels, size_t *labels_len); +int dup_security_opt(const char *src, char ***dst, size_t *len); + +#ifdef __cplusplus +} +#endif + +#endif /* __SELINUX_LABLE_H */ diff --git a/src/services/execution/spec/specs.c b/src/services/execution/spec/specs.c index f2fdb20..e0cf75b 100644 --- a/src/services/execution/spec/specs.c +++ b/src/services/execution/spec/specs.c @@ -45,6 +45,7 @@ #include "image.h" #include "path.h" #include "constants.h" +#include "selinux_label.h" #ifndef CLONE_NEWUTS #define CLONE_NEWUTS 0x04000000 @@ -206,7 +207,7 @@ static int make_annotations_cgroup_dir(const container_config *container_spec, c path = default_cgroup_parent; } if (path == NULL) { - goto out; + path = "/isulad"; } if (cleanpath(path, cleaned, sizeof(cleaned)) == NULL) { ERROR("Failed to clean path: %s", path); @@ -1016,6 +1017,25 @@ out: return ret; } +static int merge_memory_swappiness(oci_runtime_spec *oci_spec, uint64_t *memory_swappiness) +{ + int ret = 0; + + ret = make_sure_oci_spec_linux_resources_mem(oci_spec); + if (ret < 0) { + goto out; + } + + if (memory_swappiness == NULL) { + oci_spec->linux->resources->memory->swappiness = (uint64_t)(-1); + } else { + oci_spec->linux->resources->memory->swappiness = *memory_swappiness; + } + +out: + return ret; +} + static int merge_conf_cgroup_memory(oci_runtime_spec *oci_spec, const host_config *host_spec) { int ret = 0; @@ -1068,6 +1088,12 @@ static int merge_conf_cgroup_memory(oci_runtime_spec *oci_spec, const host_confi } } + ret = merge_memory_swappiness(oci_spec, host_spec->memory_swappiness); + if (ret != 0) { + ERROR("Failed to merge cgroup memory_swappiness"); + goto out; + } + out: return ret; } @@ -1221,6 +1247,11 @@ int merge_conf_cgroup(oci_runtime_spec *oci_spec, const host_config *host_spec) { int ret = 0; + if (oci_spec == NULL || host_spec == NULL) { + ret = -1; + goto out; + } + ret = merge_conf_cgroup_cpu(oci_spec, host_spec); if (ret != 0) { goto out; @@ -1657,10 +1688,284 @@ out: return ret; } -static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spec) +static int split_security_opt(const char *security_opt, char ***items, size_t *items_size) { int ret = 0; + if (strings_contains_any(security_opt, "=")) { + *items = util_string_split_n(security_opt, '=', 2); + if (*items == NULL) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + *items_size = util_array_len((const char **)*items); + } else if (strings_contains_any(security_opt, ":")) { + *items = util_string_split_n(security_opt, ':', 2); + if (*items == NULL) { + ERROR("Out of memory"); + ret = -1; + goto out; + } + *items_size = util_array_len((const char **)*items); + WARN("Security options with `:` as a separator are deprecated and will be completely unsupported" + " in new version, use `=` instead."); + } + +out: + return ret; +} + +int parse_security_opt(const host_config *host_spec, bool *no_new_privileges, + char ***label_opts, size_t *label_opts_len, + char **seccomp_profile) +{ + int ret = 0; + size_t i; + char **items = NULL; + size_t items_size = 0; + + if (host_spec->security_opt == NULL || host_spec->security_opt_len == 0) { + return 0; + } + if (host_spec->security_opt_len > LIST_SIZE_MAX) { + ERROR("Too many security option to add, the limit is %d", LIST_SIZE_MAX); + isulad_set_error_message("Too many security option to add, the limit is %d", LIST_SIZE_MAX); + ret = -1; + goto out; + } + + for (i = 0; i < host_spec->security_opt_len; i++) { + if (strcmp(host_spec->security_opt[i], "no-new-privileges") == 0) { + *no_new_privileges = true; + continue; + } else if (strcmp(host_spec->security_opt[i], "disable") == 0) { + ret = util_array_append(label_opts, "disable"); + if (ret != 0) { + ERROR("Failed to append disable label"); + ret = -1; + goto out; + } + (*label_opts_len)++; + continue; + } + + if (split_security_opt(host_spec->security_opt[i], &items, &items_size)) { + ret = -1; + goto out; + } + + if (items_size != 2) { + ERROR("invalid --security-opt: %s", host_spec->security_opt[i]); + ret = -1; + goto out; + } + + if (strcmp(items[0], "label") == 0) { + ret = util_array_append(label_opts, items[1]); + if (ret != 0) { + ERROR("Failed to append label"); + ret = -1; + goto out; + } + (*label_opts_len)++; + } else if (strcmp(items[0], "seccomp") == 0) { + free(*seccomp_profile); + *seccomp_profile = util_strdup_s(items[1]); + } else { + ERROR("invalid --security-opt: %s", host_spec->security_opt[i]); + ret = -1; + goto out; + } + util_free_array(items); + items = NULL; + } + +out: + util_free_array(items); + return ret; +} + +static int to_host_config_selinux_labels(const char **labels, size_t len, char ***dst, size_t *dst_len) +{ + int ret = 0; + size_t i; + char *item = NULL; + + for (i = 0; i < len; i++) { + item = util_string_append(labels[i], "label="); + if (item == NULL) { + ERROR("Failed to append string"); + ret = -1; + goto out; + } + if (util_array_append(dst, item) != 0) { + ERROR("Failed to append label"); + ret = -1; + goto out; + } + } + *dst_len = util_array_len((const char **)*dst); + +out: + free(item); + return ret; +} + +static int handle_host_or_privileged_mode(host_config *hc) +{ + int ret = 0; + char **labels = NULL; + size_t labels_len = 0; + + if (get_disable_security_opt(&labels, &labels_len) != 0) { + ret = -1; + goto out; + } + + if (to_host_config_selinux_labels((const char **)labels, labels_len, + &hc->security_opt, &hc->security_opt_len) != 0) { + ret = -1; + goto out; + } + +out: + util_free_array(labels); + return ret; +} + +static int handle_ipc_pid_label(host_config *hc, const char **ipc_label, size_t ipc_label_len, + const char **pid_label, size_t pid_label_len) +{ + int ret = 0; + size_t i; + + if (pid_label != NULL && ipc_label != NULL) { + if (pid_label_len != ipc_label_len) { + ERROR("--ipc and --pid containers SELinux labels aren't the same"); + ret = -1; + goto out; + } + for (i = 0; i < pid_label_len; i++) { + if (strcmp(pid_label[i], ipc_label[i]) != 0) { + ERROR("--ipc and --pid containers SELinux labels aren't the same"); + ret = -1; + goto out; + } + } + if (to_host_config_selinux_labels((const char **)pid_label, pid_label_len, + &hc->security_opt, &hc->security_opt_len) != 0) { + ret = -1; + goto out; + } + } + +out: + return ret; +} + +static int handle_connected_container_mode(host_config *hc) +{ + int ret = 0; + char **ipc_label = NULL; + size_t ipc_label_len = 0; + char **pid_label = NULL; + size_t pid_label_len = 0; + + char *ipc_container = connected_container(hc->ipc_mode); + char *pid_container = connected_container(hc->pid_mode); + if (ipc_container != NULL) { + char *ipc_process_label = get_container_process_label(ipc_container); + if (dup_security_opt(ipc_process_label, &ipc_label, &ipc_label_len) != 0) { + free(ipc_process_label); + ret = -1; + goto out; + } + if (pid_container == NULL) { + if (to_host_config_selinux_labels((const char **)ipc_label, ipc_label_len, &hc->security_opt, + &hc->security_opt_len) != 0) { + free(ipc_process_label); + ret = -1; + goto out; + } + } + free(ipc_process_label); + } + + if (pid_container != NULL) { + char *pid_process_label = get_container_process_label(pid_container); + + if (dup_security_opt(pid_process_label, &pid_label, &pid_label_len) != 0) { + free(pid_process_label); + ret = -1; + goto out; + } + if (ipc_container == NULL) { + if (to_host_config_selinux_labels((const char **)pid_label, pid_label_len, &hc->security_opt, + &hc->security_opt_len) != 0) { + free(pid_process_label); + ret = -1; + goto out; + } + } + free(pid_process_label); + } + + if (handle_ipc_pid_label(hc, (const char **)ipc_label, ipc_label_len, + (const char **)pid_label, pid_label_len) != 0) { + ret = -1; + goto out; + } + +out: + util_free_array(ipc_label); + util_free_array(pid_label); + free(ipc_container); + free(pid_container); + return ret; +} + +static int generate_security_opt(host_config *hc) +{ + size_t i; + + for (i = 0; i < hc->security_opt_len; i++) { + char **items = util_string_split(hc->security_opt[i], '='); + if (*items == NULL) { + ERROR("Out of memory"); + return -1; + } + size_t len = util_array_len((const char **)(items)); + if (len != 0 && strcmp(items[0], "label") == 0) { + util_free_array(items); + return 0; + } + util_free_array(items); + } + + if (is_host(hc->ipc_mode) || is_host(hc->pid_mode) || hc->privileged) { + return handle_host_or_privileged_mode(hc); + } + + return handle_connected_container_mode(hc); +} + + +static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spec, + container_config_v2_common_config *v2_spec) +{ + int ret = 0; + bool no_new_privileges = false; + char **label_opts = NULL; + size_t label_opts_len = 0; + char *seccomp_profile = NULL; + + ret = generate_security_opt(host_spec); + if (ret != 0) { + ERROR("Failed to generate security opt"); + goto out; + } + ret = merge_caps(oci_spec, (const char **)host_spec->cap_add, host_spec->cap_add_len, (const char **)host_spec->cap_drop, host_spec->cap_drop_len); if (ret) { @@ -1674,14 +1979,37 @@ static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spe goto out; } + ret = parse_security_opt(host_spec, &no_new_privileges, &label_opts, + &label_opts_len, &seccomp_profile); + if (ret != 0) { + ERROR("Failed to parse security opt"); + goto out; + } + // merge external parameter - ret = merge_seccomp(oci_spec, host_spec); + ret = merge_seccomp(oci_spec, seccomp_profile); if (ret != 0) { ERROR("Failed to merge user seccomp file"); goto out; } + v2_spec->seccomp_profile = util_strdup_s(seccomp_profile); + + ret = merge_no_new_privileges(oci_spec, no_new_privileges); + if (ret != 0) { + ERROR("Failed to merge no new privileges"); + goto out; + } + v2_spec->no_new_privileges = no_new_privileges; + + ret = merge_selinux(oci_spec, v2_spec, (const char **)label_opts, label_opts_len); + if (ret != 0) { + ERROR("Failed to merge selinux config"); + goto out; + } out: + util_free_array(label_opts); + free(seccomp_profile); return ret; } @@ -1698,6 +2026,11 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, } v2_spec->base_fs = util_strdup_s(real_rootfs); + ret = merge_security_conf(oci_spec, host_spec, v2_spec); + if (ret != 0) { + ERROR("Failed to merge user security config"); + goto out; + } ret = merge_resources_conf(oci_spec, host_spec, v2_spec); if (ret != 0) { @@ -1716,12 +2049,6 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, goto out; } - ret = merge_security_conf(oci_spec, host_spec); - if (ret != 0) { - ERROR("Failed to merge user seccomp file"); - goto out; - } - /* settings for system container */ ret = merge_settings_for_system_container(oci_spec, host_spec, v2_spec->config); if (ret != 0) { @@ -1748,12 +2075,6 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, goto out; } - ret = merge_no_new_privileges(oci_spec, host_spec); - if (ret != 0) { - ERROR("Failed to merge no new privileges"); - goto out; - } - ret = make_userns_remap(oci_spec, host_spec->user_remap); if (ret != 0) { ERROR("Failed to make user remap for container"); @@ -1764,6 +2085,44 @@ out: return ret; } +int merge_oci_cgroups_path(const char *id, oci_runtime_spec *oci_spec, const host_config *host_spec) +{ + int ret = 0; + char *default_cgroup_parent = NULL; + char *path = NULL; + + if (id == NULL || oci_spec == NULL || host_spec == NULL) { + ERROR("Invalid arguments"); + ret = -1; + goto out; + } + + if (make_sure_oci_spec_linux(oci_spec) != 0) { + ERROR("Failed to make oci spec linux"); + ret = -1; + goto out; + } + + default_cgroup_parent = conf_get_isulad_cgroup_parent(); + path = default_cgroup_parent; + if (host_spec->cgroup_parent != NULL) { + path = host_spec->cgroup_parent; + } + + if (path == NULL) { + free(oci_spec->linux->cgroups_path); + oci_spec->linux->cgroups_path = util_path_join("/isulad", id); + return 0; + } + + free(oci_spec->linux->cgroups_path); + oci_spec->linux->cgroups_path = util_path_join(path, id); + +out: + UTIL_FREE_AND_SET_NULL(default_cgroup_parent); + return ret; +} + /* merge the default config with host config and custom config */ int merge_global_config(oci_runtime_spec *oci_spec) { @@ -1833,7 +2192,7 @@ int save_oci_config(const char *id, const char *rootpath, const oci_runtime_spec goto out_free; } - if (util_write_file(file_path, json_container, strlen(json_container)) != 0) { + if (util_write_file(file_path, json_container, strlen(json_container), DEFAULT_SECURE_FILE_MODE) != 0) { ERROR("write json container failed: %s", strerror(errno)); ret = -1; goto out_free; diff --git a/src/services/execution/spec/specs.h b/src/services/execution/spec/specs.h index 1b64574..a5fec40 100644 --- a/src/services/execution/spec/specs.h +++ b/src/services/execution/spec/specs.h @@ -22,16 +22,27 @@ #include "oci_runtime_hooks.h" #include "oci_runtime_spec.h" +#ifdef __cplusplus +extern "C" { +#endif int merge_all_specs(host_config *host_spec, const char *real_rootfs, container_config_v2_common_config *v2_spec, oci_runtime_spec *oci_spec); - +int merge_oci_cgroups_path(const char *id, oci_runtime_spec *oci_spec, + const host_config *host_spec); int merge_global_config(oci_runtime_spec *oci_spec); oci_runtime_spec *load_oci_config(const char *rootpath, const char *name); oci_runtime_spec *default_spec(bool system_container); int merge_conf_cgroup(oci_runtime_spec *oci_spec, const host_config *host_spec); int save_oci_config(const char *id, const char *rootpath, const oci_runtime_spec *oci_spec); +int parse_security_opt(const host_config *host_spec, bool *no_new_privileges, + char ***label_opts, size_t *label_opts_len, + char **seccomp_profile); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/services/execution/spec/specs_extend.c b/src/services/execution/spec/specs_extend.c index 737069e..def3978 100644 --- a/src/services/execution/spec/specs_extend.c +++ b/src/services/execution/spec/specs_extend.c @@ -88,6 +88,10 @@ MERGE_HOOKS_ITEM_DEF(poststop) int merge_hooks(oci_runtime_spec_hooks *dest, oci_runtime_spec_hooks *src) { + if (dest == NULL || src == NULL) { + return -1; + } + if (merge_prestart_conf(dest, src) || merge_poststart_conf(dest, src) || merge_poststop_conf(dest, src)) { return -1; } @@ -589,11 +593,12 @@ static int proc_by_fpasswd(FILE *f_passwd, const char *user, defs_process_user * userfound = b_user_found(user, pwbufp); // Take the first match as valid user if (userfound) { + // oci spec donot use username spec on linux free(puser->username); - puser->username = util_strdup_s(pwbufp->pw_name); + puser->username = NULL; puser->uid = pwbufp->pw_uid; puser->gid = pwbufp->pw_gid; - *matched_username = puser->username; + *matched_username = util_strdup_s(pwbufp->pw_name); break; } errval = fgetpwent_r(f_passwd, &pw, buf, sizeof(buf), &pwbufp); @@ -789,6 +794,7 @@ static int get_exec_user(const char *username, FILE *f_passwd, FILE *f_group, de } cleanup: + free(matched_username); free(tmp); return ret; } diff --git a/src/services/execution/spec/specs_mount.c b/src/services/execution/spec/specs_mount.c index df99cb4..2c1afd1 100644 --- a/src/services/execution/spec/specs_mount.c +++ b/src/services/execution/spec/specs_mount.c @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -41,6 +43,8 @@ #include "parse_common.h" #include "specs_mount.h" #include "specs_extend.h" +#include "containers_store.h" +#include "selinux_label.h" static int get_devices(const char *dir, char ***devices, size_t *device_len, int recursive_depth); @@ -696,7 +700,10 @@ defs_mount *parse_volume(const char *volume) defs_mount *mount_element = NULL; char **modes = NULL; char dstpath[PATH_MAX] = { 0x00 }; - char *rw = "rw", *pro = DefaultPropagationMode; + char *rw = "rw"; + char *pro = DefaultPropagationMode; + char *label = NULL; + size_t options_len = 3; ret = check_volume_element(volume); if (ret != 0) { @@ -721,7 +728,7 @@ defs_mount *parse_volume(const char *volume) } else if (util_valid_propagation_mode(modes[i])) { pro = modes[i]; } else if (util_valid_label_mode(modes[i])) { - WARN("Valid mode '%s' found but not configured for now", modes[i]); + label = modes[i]; } else if (util_valid_copy_mode(modes[i])) { WARN("Valid mode '%s' found but not configured for now", modes[i]); } @@ -734,8 +741,10 @@ defs_mount *parse_volume(const char *volume) } free(mount_element->destination); mount_element->destination = util_strdup_s(dstpath); - - mount_element->options = util_common_calloc_s(3 * sizeof(char *)); + if (label != NULL) { + options_len++; + } + mount_element->options = util_common_calloc_s(options_len * sizeof(char *)); if (mount_element->options == NULL) { ERROR("Out of memory"); mount_element->options_len = 0; @@ -745,7 +754,10 @@ defs_mount *parse_volume(const char *volume) mount_element->options[0] = util_strdup_s(rw); mount_element->options[1] = util_strdup_s(pro); mount_element->options[2] = util_strdup_s("rbind"); - mount_element->options_len = 3; + if (options_len >= 4) { + mount_element->options[3] = util_strdup_s(label); + } + mount_element->options_len = options_len; mount_element->type = util_strdup_s("bind"); free_out: @@ -1918,14 +1930,18 @@ out_free: return ret; } -static int change_dev_shm_size(oci_runtime_spec *oci_spec, int64_t shm_size) +static int change_dev_shm_size(oci_runtime_spec *oci_spec, host_config *host_spec) { size_t i = 0; size_t j = 0; char size_opt[MOUNT_PROPERTIES_SIZE] = { 0 }; char *tmp = NULL; - int nret = snprintf(size_opt, sizeof(size_opt), "size=%lld", (long long int)shm_size); + if (is_none(host_spec->ipc_mode)) { + return 0; + } + + int nret = snprintf(size_opt, sizeof(size_opt), "size=%lld", (long long int)host_spec->shm_size); if (nret < 0 || (size_t)nret >= sizeof(size_opt)) { ERROR("Out of memory"); return -1; @@ -1976,13 +1992,15 @@ static inline bool is_mount_destination_hostname(const char *destination) * if not exists: append mounts to ocispec by v2_spec * if exists: replace the source in v2_spec */ -static int append_network_files_mounts(oci_runtime_spec *oci_spec, container_config_v2_common_config *v2_spec) +static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config *host_spec, + container_config_v2_common_config *v2_spec) { int ret = 0; size_t i = 0; bool has_hosts_mount = false; bool has_resolv_mount = false; bool has_hostname_mount = false; + bool share = is_container(host_spec->network_mode); for (i = 0; i < oci_spec->mounts_len; i++) { if (is_mount_destination_hosts(oci_spec->mounts[i]->destination)) { @@ -2002,30 +2020,293 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, container_con } } - /* add network config files */ - if (!has_hosts_mount && !mount_file(oci_spec, v2_spec->hosts_path, ETC_HOSTS)) { - ERROR("Merge hosts mount failed"); - ret = -1; - goto out; + if (!util_file_exists(v2_spec->hosts_path)) { + WARN("HostsPath set to %s, but can't stat this filename (err = %v); skipping", v2_spec->resolv_conf_path); + } else { + /* add network config files */ + if (!has_hosts_mount) { + if (relabel(v2_spec->hosts_path, v2_spec->mount_label, share) != 0) { + ERROR("Error to relabel hosts path: %s", v2_spec->hosts_path); + ret = -1; + goto out; + } + if (!mount_file(oci_spec, v2_spec->hosts_path, ETC_HOSTS)) { + ERROR("Merge hosts mount failed"); + ret = -1; + goto out; + } + } } - if (!has_resolv_mount && - !mount_file(oci_spec, v2_spec->resolv_conf_path, RESOLV_CONF_PATH)) { - ERROR("Merge resolv.conf mount failed"); - ret = -1; - goto out; + if (!util_file_exists(v2_spec->resolv_conf_path)) { + WARN("ResolvConfPath set to %s, but can't stat this filename (err = %v); skipping", v2_spec->resolv_conf_path); + } else { + if (!has_resolv_mount) { + if (relabel(v2_spec->resolv_conf_path, v2_spec->mount_label, share) != 0) { + ERROR("Error to relabel resolv.conf path: %s", v2_spec->resolv_conf_path); + ret = -1; + goto out; + } + if (!mount_file(oci_spec, v2_spec->resolv_conf_path, RESOLV_CONF_PATH)) { + ERROR("Merge resolv.conf mount failed"); + ret = -1; + goto out; + } + } } - if (!has_hostname_mount && - !mount_file(oci_spec, v2_spec->hostname_path, ETC_HOSTNAME)) { - ERROR("Merge hostname mount failed"); - ret = -1; - goto out; + if (!util_file_exists(v2_spec->hostname_path)) { + WARN("HostnamePath set to %s, but can't stat this filename (err = %v); skipping", v2_spec->resolv_conf_path); + } else { + if (!has_hostname_mount) { + if (relabel(v2_spec->hostname_path, v2_spec->mount_label, share) != 0) { + ERROR("Error to relabel hostname path: %s", v2_spec->hostname_path); + return -1; + } + if (!mount_file(oci_spec, v2_spec->hostname_path, ETC_HOSTNAME)) { + ERROR("Merge hostname mount failed"); + ret = -1; + goto out; + } + } } out: return ret; } +static int chown_for_shm(const char *shm_path, const char *user_remap) +{ + unsigned int host_uid = 0; + unsigned int host_gid = 0; + unsigned int size = 0; + + if (shm_path == NULL) { + return 0; + } + + if (user_remap != NULL) { + if (util_parse_user_remap(user_remap, &host_uid, &host_gid, &size)) { + ERROR("Failed to split string '%s'.", user_remap); + return -1; + } + if (chown(shm_path, host_uid, host_gid) != 0) { + ERROR("Failed to chown host path '%s'.", shm_path); + return -1; + } + } + return 0; +} + +static char *get_prepare_share_shm_path(const char *truntime, const char *cid) +{ +#define SHM_MOUNT_FILE_NAME "/mounts/shm/" + char *c_root_path = NULL; + size_t slen = 0; + char *spath = NULL; + int nret = 0; + + if (truntime == NULL) { + truntime = "lcr"; + } + c_root_path = conf_get_routine_rootdir(truntime); + if (c_root_path == NULL) { + goto err_out; + } + + // c_root_path + "/" + cid + "/mounts/shm" + if (strlen(c_root_path) > (((PATH_MAX - strlen(cid)) - 1) - strlen(SHM_MOUNT_FILE_NAME)) - 1) { + ERROR("Too large path"); + goto err_out; + } + slen = strlen(c_root_path) + 1 + strlen(cid) + strlen(SHM_MOUNT_FILE_NAME) + 1; + spath = util_smart_calloc_s(sizeof(char), slen); + if (spath == NULL) { + ERROR("Out of memory"); + goto err_out; + } + + nret = sprintf(spath, "%s/%s/mounts/shm/", c_root_path, cid); + if (nret < 0) { + ERROR("Sprintf failed"); + goto err_out; + } + + free(c_root_path); + return spath; + +err_out: + free(spath); + free(c_root_path); + return NULL; +} + +static bool has_mount_shm(host_config *host_spec, container_config_v2_common_config *v2_spec) +{ + container_t *cont = NULL; + bool ret = false; + + cont = util_common_calloc_s(sizeof(container_t)); + if (cont == NULL) { + ERROR("Out of memory"); + goto out; + } + cont->common_config = v2_spec; + cont->hostconfig = host_spec; + + ret = has_mount_for(cont, "/dev/shm"); + + cont->common_config = NULL; + cont->hostconfig = NULL; +out: + free(cont); + return ret; +} + +static int prepare_share_shm(oci_runtime_spec *oci_spec, host_config *host_spec, + container_config_v2_common_config *v2_spec) +{ +#define MAX_PROPERTY_LEN 64 + char shmproperty[MAX_PROPERTY_LEN] = {0}; + int ret = -1; + int nret = 0; + bool has_mount = false; + char *spath = NULL; + + // has mount for /dev/shm + if (has_mount_shm(host_spec, v2_spec)) { + return 0; + } + + spath = get_prepare_share_shm_path(host_spec->runtime, v2_spec->id); + if (spath == NULL) { + goto out; + } + + nret = util_mkdir_p(spath, 0700); + if (nret != 0) { + ERROR("Build shm dir failed"); + goto out; + } + nret = sprintf(shmproperty, "mode=1777,size=%"PRId64, host_spec->shm_size); + if (nret < 0) { + ERROR("Sprintf failed"); + goto out; + } + + nret = mount("shm", spath, "tmpfs", MS_NOEXEC | MS_NODEV | MS_NOSUID, shmproperty); + if (nret < 0) { + ERROR("Mount %s failed: %s", spath, strerror(errno)); + goto out; + } + has_mount = true; + + nret = chown_for_shm(spath, host_spec->user_remap); + if (nret != 0) { + goto out; + } + + v2_spec->shm_path = spath; + spath = NULL; + ret = 0; +out: + if (ret != 0 && has_mount) { + (void)umount(spath); + } + free(spath); + return ret; +} + +static bool add_shm_mount(oci_runtime_spec *container, const char *shm_path) +{ + char **options = NULL; + size_t options_len = 3; + bool ret = false; + defs_mount *tmp_mounts = NULL; + + if (options_len > SIZE_MAX / sizeof(char *)) { + ERROR("Invalid option size"); + return ret; + } + options = util_common_calloc_s(options_len * sizeof(char *)); + if (options == NULL) { + ERROR("Out of memory"); + goto out_free; + } + options[0] = util_strdup_s("rbind"); + options[1] = util_strdup_s("rprivate"); + // default shm size is 64MB + options[2] = util_strdup_s("size=65536k"); + /* generate mount node */ + tmp_mounts = util_common_calloc_s(sizeof(defs_mount)); + if (tmp_mounts == NULL) { + ERROR("Malloc tmp_mounts memory failed"); + goto out_free; + } + + tmp_mounts->destination = util_strdup_s("/dev/shm"); + tmp_mounts->source = util_strdup_s(shm_path); + tmp_mounts->type = util_strdup_s("bind"); + tmp_mounts->options = options; + tmp_mounts->options_len = options_len; + options = NULL; + + /* expand mount array */ + if (!mounts_expand(container, 1)) { + goto out_free; + } + /* add a new mount node */ + container->mounts[container->mounts_len - 1] = tmp_mounts; + + ret = true; +out_free: + + if (!ret) { + util_free_array(options); + free_defs_mount(tmp_mounts); + } + return ret; +} + +#define SHM_MOUNT_POINT "/dev/shm" +static int setup_ipc_dirs(oci_runtime_spec *oci_spec, host_config *host_spec, + container_config_v2_common_config *v2_spec) +{ + int ret = 0; + container_t *cont = NULL; + char *tmp_cid = NULL; + char *right_path = NULL; + + // setup shareable dirs + if (host_spec->ipc_mode == NULL || is_shareable(host_spec->ipc_mode)) { + return prepare_share_shm(oci_spec, host_spec, v2_spec); + } + + if (is_container(host_spec->ipc_mode)) { + tmp_cid = connected_container(host_spec->ipc_mode); + cont = containers_store_get(tmp_cid); + if (cont == NULL) { + ERROR("Invalid share path: %s", host_spec->ipc_mode); + ret = -1; + goto out; + } + right_path = util_strdup_s(cont->common_config->shm_path); + container_unref(cont); + } else if (is_host(host_spec->ipc_mode)) { + if (!util_file_exists(SHM_MOUNT_POINT)) { + ERROR("/dev/shm is not mounted, but must be for --ipc=host"); + ret = -1; + goto out; + } + right_path = util_strdup_s(SHM_MOUNT_POINT); + } + + free(v2_spec->shm_path); + v2_spec->shm_path = right_path; +out: + free(tmp_cid); + return ret; +} + int merge_conf_mounts(oci_runtime_spec *oci_spec, host_config *host_spec, container_config_v2_common_config *v2_spec) { @@ -2062,12 +2343,24 @@ int merge_conf_mounts(oci_runtime_spec *oci_spec, host_config *host_spec, } } - if (host_spec->shm_size >= 0) { - if (host_spec->shm_size == 0) { - host_spec->shm_size = DEFAULT_SHM_SIZE; - } + if (host_spec->shm_size == 0) { + host_spec->shm_size = DEFAULT_SHM_SIZE; + } - ret = change_dev_shm_size(oci_spec, host_spec->shm_size); + /* setup ipc dir */ + if (setup_ipc_dirs(oci_spec, host_spec, v2_spec) != 0) { + ret = -1; + goto out; + } + + /* add ipc mount */ + if (v2_spec->shm_path != NULL) { + // check whether duplication + add_shm_mount(oci_spec, v2_spec->shm_path); + } + + if (host_spec->shm_size > 0) { + ret = change_dev_shm_size(oci_spec, host_spec); if (ret) { ERROR("Failed to set dev shm size"); goto out; @@ -2075,7 +2368,7 @@ int merge_conf_mounts(oci_runtime_spec *oci_spec, host_config *host_spec, } if (!host_spec->system_container) { - ret = append_network_files_mounts(oci_spec, v2_spec); + ret = append_network_files_mounts(oci_spec, host_spec, v2_spec); if (ret) { ERROR("Failed to append network mounts"); goto out; diff --git a/src/services/execution/spec/specs_security.c b/src/services/execution/spec/specs_security.c index b947b14..d471a39 100644 --- a/src/services/execution/spec/specs_security.c +++ b/src/services/execution/spec/specs_security.c @@ -44,6 +44,8 @@ #include "container_def.h" #include "libisulad.h" #include "specs_extend.h" +#include "selinux_label.h" +#include "specs.h" #define MAX_CAP_LEN 32 @@ -859,29 +861,52 @@ out: return ret; } -int merge_no_new_privileges(oci_runtime_spec *oci_spec, const host_config *host_spec) +int merge_no_new_privileges(oci_runtime_spec *oci_spec, bool value) { int ret = 0; - size_t i = 0; ret = make_sure_oci_spec_process(oci_spec); if (ret < 0) { goto out; } - oci_spec->process->no_new_privileges = false; - if (host_spec->security_opt == NULL || host_spec->security_opt_len == 0) { - return 0; + oci_spec->process->no_new_privileges = value; + +out: + return ret; +} + + +int merge_selinux(oci_runtime_spec *oci_spec, container_config_v2_common_config *v2_spec, + const char **label_opts, size_t label_opts_len) +{ + char *process_label = NULL; + char *mount_label = NULL; + + int ret = make_sure_oci_spec_process(oci_spec); + if (ret < 0) { + goto out; } - for (i = 0; i < host_spec->security_opt_len; i++) { - if (strcmp(host_spec->security_opt[i], "no-new-privileges") == 0) { - oci_spec->process->no_new_privileges = true; - break; - } + if (init_label(label_opts, label_opts_len, &process_label, &mount_label) != 0) { + ERROR("Failed to append label"); + ret = -1; + goto out; + } + + if (mount_label != NULL) { + oci_spec->linux->mount_label = util_strdup_s(mount_label); + v2_spec->mount_label = util_strdup_s(mount_label); + } + + if (process_label != NULL) { + oci_spec->process->selinux_label = util_strdup_s(process_label); + v2_spec->process_label = util_strdup_s(process_label); } out: + free(process_label); + free(mount_label); return ret; } @@ -960,6 +985,10 @@ int adapt_settings_for_system_container(oci_runtime_spec *oci_spec, const host_c }; char **adds = NULL; size_t adds_len = 0; + bool no_new_privileges = false; + char **label_opts = NULL; + size_t label_opts_len = 0; + char *seccomp_profile = NULL; ret = get_adds_cap_for_system_container(host_spec, &adds, &adds_len); if (ret != 0) { @@ -975,6 +1004,17 @@ int adapt_settings_for_system_container(oci_runtime_spec *oci_spec, const host_c goto out; } + ret = parse_security_opt(host_spec, &no_new_privileges, &label_opts, + &label_opts_len, &seccomp_profile); + if (ret != 0) { + ERROR("Failed to parse security opt"); + goto out; + } + /* do not append to seccomp if seccomp profile is NULL or unconfined */ + if (seccomp_profile == NULL || strcmp(seccomp_profile, "unconfined") == 0) { + goto out; + } + ret = make_sure_oci_spec_linux(oci_spec); if (ret < 0) { goto out; @@ -997,58 +1037,44 @@ int adapt_settings_for_system_container(oci_runtime_spec *oci_spec, const host_c goto out; } out: + util_free_array(label_opts); + free(seccomp_profile); free_adds_cap_for_system_container(adds, adds_len); return ret; } -int merge_seccomp(oci_runtime_spec *oci_spec, const host_config *host_spec) +int merge_seccomp(oci_runtime_spec *oci_spec, const char *seccomp_profile) { int ret = 0; - size_t k = 0; parser_error err = NULL; - char *seccomp_json = NULL; docker_seccomp *docker_seccomp = NULL; - if (host_spec->security_opt == NULL || host_spec->security_opt_len == 0) { + if (seccomp_profile == NULL) { return 0; } - if (host_spec->security_opt_len > LIST_SIZE_MAX) { - ERROR("Too many security option to add, the limit is %d", LIST_SIZE_MAX); - isulad_set_error_message("Too many security option to add, the limit is %d", LIST_SIZE_MAX); + ret = make_sure_oci_spec_linux(oci_spec); + if (ret < 0) { + goto out; + } + // free default seccomp + free_oci_runtime_config_linux_seccomp(oci_spec->linux->seccomp); + oci_spec->linux->seccomp = NULL; + + if (strcmp(seccomp_profile, "unconfined") == 0) { + goto out; + } + docker_seccomp = docker_seccomp_parse_data((const char *)seccomp_profile, NULL, &err); + if (docker_seccomp == NULL) { + ERROR("Failed to parse host config data:%s", err); ret = -1; goto out; } - for (k = 0; k < host_spec->security_opt_len; k++) { - if (strncmp(host_spec->security_opt[k], "seccomp=", strlen("seccomp=")) != 0) { - continue; - } - ret = make_sure_oci_spec_linux(oci_spec); - if (ret < 0) { - goto out; - } - // free default seccomp - free_oci_runtime_config_linux_seccomp(oci_spec->linux->seccomp); - oci_spec->linux->seccomp = NULL; - - seccomp_json = host_spec->security_opt[k] + strlen("seccomp") + 1; - if (strcmp(seccomp_json, "unconfined") == 0) { - continue; - } - docker_seccomp = docker_seccomp_parse_data((const char *)seccomp_json, NULL, &err); - if (docker_seccomp == NULL) { - ERROR("Failed to parse host config data:%s", err); - ret = -1; - goto out; - } - oci_spec->linux->seccomp = trans_docker_seccomp_to_oci_format(docker_seccomp, oci_spec->process->capabilities); - if (oci_spec->linux->seccomp == NULL) { - ERROR("Failed to trans docker seccomp format to oci profile"); - ret = -1; - goto out; - } - free_docker_seccomp(docker_seccomp); - docker_seccomp = NULL; + oci_spec->linux->seccomp = trans_docker_seccomp_to_oci_format(docker_seccomp, oci_spec->process->capabilities); + if (oci_spec->linux->seccomp == NULL) { + ERROR("Failed to trans docker seccomp format to oci profile"); + ret = -1; + goto out; } out: diff --git a/src/services/execution/spec/specs_security.h b/src/services/execution/spec/specs_security.h index e68d29a..658b5ec 100644 --- a/src/services/execution/spec/specs_security.h +++ b/src/services/execution/spec/specs_security.h @@ -27,9 +27,11 @@ int merge_caps(oci_runtime_spec *oci_spec, const char **adds, size_t adds_len, c int refill_oci_process_capabilities(defs_process_capabilities **caps, const char **src_caps, size_t src_caps_len); int merge_sysctls(oci_runtime_spec *oci_spec, const json_map_string_string *sysctls); -int merge_no_new_privileges(oci_runtime_spec *oci_spec, const host_config *host_spec); +int merge_no_new_privileges(oci_runtime_spec *oci_spec, bool value); int adapt_settings_for_system_container(oci_runtime_spec *oci_spec, const host_config *host_spec); -int merge_seccomp(oci_runtime_spec *oci_spec, const host_config *host_spec); +int merge_seccomp(oci_runtime_spec *oci_spec, const char *seccomp_profile); +int merge_selinux(oci_runtime_spec *oci_spec, container_config_v2_common_config *v2_spec, + const char **label_opts, size_t label_opts_len); #endif diff --git a/src/services/execution/spec/sysinfo.h b/src/services/execution/spec/sysinfo.h index 2831a53..7832564 100644 --- a/src/services/execution/spec/sysinfo.h +++ b/src/services/execution/spec/sysinfo.h @@ -22,6 +22,10 @@ #define etcOsRelease "/etc/os-release" #define altOsRelease "/usr/lib/os-release" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { bool limit; bool swap; @@ -134,5 +138,9 @@ mountinfo_t *find_mount_info(mountinfo_t **minfos, const char *dir); void free_mounts_info(mountinfo_t **minfos); +#ifdef __cplusplus +} +#endif + #endif /* __SYSINFO_H */ diff --git a/src/services/execution/spec/verify.c b/src/services/execution/spec/verify.c index 51cb29f..80054b0 100644 --- a/src/services/execution/spec/verify.c +++ b/src/services/execution/spec/verify.c @@ -33,6 +33,7 @@ #include "specs.h" #include "verify.h" #include "isulad_config.h" +#include "selinux_label.h" /* verify hook timeout */ static int verify_hook_timeout(int t) @@ -168,7 +169,7 @@ out: static inline bool is_swappiness_invalid(uint64_t swapiness) { - return (int64_t)swapiness < -1 || swapiness > 100; + return (int64_t)swapiness < -1 || (int64_t)swapiness > 100; } /* verify memory swappiness */ @@ -1459,10 +1460,10 @@ out: static int verify_custom_mount(defs_mount **mounts, size_t len) { int ret = 0; - size_t i = 0; + size_t i; defs_mount *iter = NULL; - for (; i < len; ++i) { + for (i = 0; i < len; ++i) { iter = *(mounts + i); if (iter == NULL || strcmp(iter->type, "bind")) { continue; @@ -1701,6 +1702,13 @@ static int host_config_settings_memory(const sysinfo_t *sysinfo, const host_conf goto out; } + if (hostconfig->memory_swappiness != NULL) { + ret = verify_memory_swappiness(sysinfo, *(hostconfig->memory_swappiness)); + if (ret != 0) { + goto out; + } + } + out: return ret; } @@ -1909,6 +1917,41 @@ out: return ret; } +static int relabel_mounts_if_needed(defs_mount **mounts, size_t len, const char *mount_label) +{ + int ret = 0; + size_t i, j; + defs_mount *iter = NULL; + + for (i = 0; i < len; ++i) { + bool need_relabel = false; + bool is_shared = false; + iter = *(mounts + i); + if (iter == NULL) { + continue; + } + + for (j = 0; j < iter->options_len; j++) { + if (strcmp(iter->options[j], "Z") == 0) { + need_relabel = true; + is_shared = false; + } else if (strcmp(iter->options[j], "z") == 0) { + need_relabel = true; + is_shared = true; + } + } + + if (need_relabel && relabel(iter->source, mount_label, is_shared) != 0) { + ERROR("Error setting label on mount source '%s'", iter->source); + ret = -1; + goto out; + } + } + +out: + return ret; +} + /* verify container settings start */ int verify_container_settings_start(const oci_runtime_spec *oci_spec) { @@ -1916,9 +1959,20 @@ int verify_container_settings_start(const oci_runtime_spec *oci_spec) /* verify custom mount info, ensure source path exist */ if (oci_spec->mounts != NULL && oci_spec->mounts_len > 0) { - ret = verify_custom_mount(oci_spec->mounts, oci_spec->mounts_len); + if (verify_custom_mount(oci_spec->mounts, oci_spec->mounts_len) != 0) { + ERROR("Failed to verify custom mount"); + ret = -1; + goto out; + } + if (relabel_mounts_if_needed(oci_spec->mounts, oci_spec->mounts_len, + oci_spec->linux->mount_label) != 0) { + ERROR("Failed to relabel mount"); + ret = -1; + goto out; + } } +out: return ret; } diff --git a/src/services/execution/spec/verify.h b/src/services/execution/spec/verify.h index e1426b9..6801a90 100644 --- a/src/services/execution/spec/verify.h +++ b/src/services/execution/spec/verify.h @@ -17,6 +17,11 @@ #include "oci_runtime_spec.h" #include "host_config.h" +#include "container_config.h" + +#ifdef __cplusplus +extern "C" { +#endif int verify_container_settings(const oci_runtime_spec *container); @@ -28,6 +33,9 @@ int verify_host_config_settings(host_config *hostconfig, bool update); int verify_health_check_parameter(const container_config *container_spec); +#ifdef __cplusplus +} +#endif #endif /* __VERIFY_H */ diff --git a/src/services/graphdriver/devmapper/driver_devmapper.c b/src/services/graphdriver/devmapper/driver_devmapper.c index 4bd765c..c82bd3f 100644 --- a/src/services/graphdriver/devmapper/driver_devmapper.c +++ b/src/services/graphdriver/devmapper/driver_devmapper.c @@ -37,6 +37,10 @@ int devmapper_parse_options(struct graphdriver *driver, const char **options, si { size_t i = 0; + if (driver == NULL) { + return -1; + } + for (i = 0; options != NULL && i < options_len; i++) { char *dup = NULL; char *p = NULL; @@ -69,8 +73,9 @@ int devmapper_parse_options(struct graphdriver *driver, const char **options, si } else if (strcasecmp(dup, "dm.min_free_space") == 0) { long converted = 0; ret = util_parse_percent_string(val, &converted); - if (ret != 0) { + if (ret != 0 || converted == 100) { isulad_set_error_message("Invalid min free space: '%s': %s", val, strerror(-ret)); + ret = -1; } } else if (strcasecmp(dup, "dm.basesize") == 0) { int64_t converted = 0; diff --git a/src/services/image/image_cb.c b/src/services/image/image_cb.c index ea13a4f..61a0001 100644 --- a/src/services/image/image_cb.c +++ b/src/services/image/image_cb.c @@ -34,6 +34,7 @@ #include "isulad_config.h" #include "mediatype.h" #include "filters.h" +#include "collector.h" #ifdef ENABLE_OCI_IMAGE #include "oci_image_unix.h" #include "oci_images_store.h" @@ -114,6 +115,8 @@ static int image_load_cb(const image_load_image_request *request, EVENT("Image Event: {Object: %s, Type: Loaded}", request->file); + + (void)isulad_monitor_send_image_event(request->file, IM_LOAD); out: if (*response != NULL) { @@ -194,6 +197,7 @@ static int login_cb(const image_login_request *request, } EVENT("Image Event: {Object: %s, Type: Logined}", request->server); + (void)isulad_monitor_send_image_event(request->server, IM_LOGIN); out: if (response != NULL && *response != NULL) { @@ -271,6 +275,7 @@ static int logout_cb(const image_logout_request *request, } EVENT("Image Event: {Object: %s, Type: Logouted}", request->server); + (void)isulad_monitor_send_image_event(request->server, IM_LOGOUT); out: if (response != NULL && *response != NULL) { @@ -353,8 +358,7 @@ static int image_remove_cb(const image_delete_image_request *request, if (!util_valid_image_name(image_ref)) { ERROR("Invalid image name %s", image_ref); cc = ISULAD_ERR_INPUT; - isulad_try_set_error_message("Invalid image name:%s", - image_ref); + isulad_try_set_error_message("Invalid image name:%s", image_ref); goto out; } @@ -428,13 +432,23 @@ static int trans_one_image(image_list_images_response *response, size_t image_in } if (im_image->created != NULL) { - if (time_tz_to_seconds_nanos(im_image->created, - &(out_image->created_at->seconds), - &(out_image->created_at->nanos))) { - ERROR("Failed to translate created to seconds and nanos"); + int64_t created_nanos = 0; + types_timestamp_t timestamp; + + if (to_unix_nanos_from_str(im_image->created, &created_nanos) != 0) { + ERROR("Failed to translate created time to nanos"); ret = -1; goto out; } + + if (!unix_nanos_to_timestamp(created_nanos, ×tamp) != 0) { + ERROR("Failed to translate nanos to timestamp"); + ret = -1; + goto out; + } + + out_image->created_at->seconds = timestamp.seconds; + out_image->created_at->nanos = timestamp.nanos; } out: diff --git a/src/types_def.c b/src/types_def.c index 883f06e..bfc1769 100644 --- a/src/types_def.c +++ b/src/types_def.c @@ -836,7 +836,7 @@ int time_format_duration_ago(const char *in, char *out, size_t len) return 0; } -int time_tz_to_seconds_nanos(const char *time_tz, int64_t *seconds, int32_t *nanos) +static int time_tz_to_seconds_nanos(const char *time_tz, int64_t *seconds, int32_t *nanos) { int nret = 0; struct tm t = { 0 }; @@ -853,14 +853,9 @@ int time_tz_to_seconds_nanos(const char *time_tz, int64_t *seconds, int32_t *nan return 0; } - if (!util_valid_time_tz(time_tz)) { - ERROR("invalid time %s", time_tz); - return -1; - } - /* translate to rfc339NanoLocal */ time_str = util_strdup_s(time_tz); - time_str[strlen(time_str) - 1] = 0; /* strip last 'Z' */ + time_str[strlen(time_str) - 1] = '\0'; /* strip last 'Z' */ if (!get_tm_from_str(time_str, &t, &nano)) { ERROR("get tm from string %s failed", time_str); @@ -897,6 +892,11 @@ int to_unix_nanos_from_str(const char *str, int64_t *nanos) return 0; } + if (!util_valid_time_tz(str)) { + ERROR("invalid time %s", str); + return -1; + } + if (str[strlen(str) - 1] == 'Z') { int ret = time_tz_to_seconds_nanos(str, &ts.seconds, &ts.nanos); if (ret != 0) { diff --git a/src/types_def.h b/src/types_def.h index 7383876..711ed21 100644 --- a/src/types_def.h +++ b/src/types_def.h @@ -52,8 +52,6 @@ bool get_now_time_buffer(char *timebuffer, size_t maxsize); int get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result); -int time_tz_to_seconds_nanos(const char *time_tz, int64_t *seconds, int32_t *nanos); - int to_unix_nanos_from_str(const char *str, int64_t *nanos); bool parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index baea137..36aa6d1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,9 +1,46 @@ project(iSulad_LLT) +function(gmock_find_library _name) + find_library(${_name} + NAMES ${ARGN} + HINTS + $ENV{GMOCK_ROOT} + ${GMOCK_ROOT} + ) + mark_as_advanced(${_name}) +endfunction() + +find_path(GMOCK_INCLUDE_DIR gmock/gmock.h + HINTS + $ENV{GMOCK_ROOT}/include + ${GMOCK_ROOT}/include +) +mark_as_advanced(GMOCK_INCLUDE_DIR) + +gmock_find_library(GMOCK_LIBRARY gmock) +gmock_find_library(GMOCK_LIBRARY_DEBUG gmockd) +gmock_find_library(GMOCK_MAIN_LIBRARY gmock_main) +gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_maind) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMock DEFAULT_MSG GMOCK_LIBRARY GMOCK_INCLUDE_DIR GMOCK_MAIN_LIBRARY) + +if(GMOCK_FOUND) + set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR}) + set(GMOCK_BOTH_LIBRARIES ${GMOCK_LIBRARIES} ${GMOCK_MAIN_LIBRARIES}) +endif() + # setup testing find_package(Threads REQUIRED) find_package(GTest REQUIRED) +include_directories(${GTEST_INCLUDE_DIR}) +include_directories(${GMOCK_INCLUDE_DIRS}) + add_subdirectory(cutils) add_subdirectory(image) add_subdirectory(path) +add_subdirectory(cmd) +add_subdirectory(runtime) +add_subdirectory(specs) +add_subdirectory(services) diff --git a/test/cmd/CMakeLists.txt b/test/cmd/CMakeLists.txt new file mode 100644 index 0000000..69dac71 --- /dev/null +++ b/test/cmd/CMakeLists.txt @@ -0,0 +1,4 @@ +project(iSulad_LLT) + +add_subdirectory(isula) +add_subdirectory(isulad-shim) diff --git a/test/cmd/isula/CMakeLists.txt b/test/cmd/isula/CMakeLists.txt new file mode 100644 index 0000000..b921c1c --- /dev/null +++ b/test/cmd/isula/CMakeLists.txt @@ -0,0 +1,4 @@ +project(iSulad_LLT) + +add_subdirectory(infomation) +add_subdirectory(extend) diff --git a/test/cmd/isula/extend/CMakeLists.txt b/test/cmd/isula/extend/CMakeLists.txt new file mode 100644 index 0000000..6546ebc --- /dev/null +++ b/test/cmd/isula/extend/CMakeLists.txt @@ -0,0 +1,4 @@ +project(iSulad_LLT) + +add_subdirectory(pause) +add_subdirectory(resume) diff --git a/test/cmd/isula/extend/pause/CMakeLists.txt b/test/cmd/isula/extend/pause/CMakeLists.txt new file mode 100644 index 0000000..6ddddee --- /dev/null +++ b/test/cmd/isula/extend/pause/CMakeLists.txt @@ -0,0 +1,55 @@ +project(iSulad_LLT) + +SET(EXE pause_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/commander.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisula.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/types_def.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/container_def.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/error.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client/isula_connect.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/extend/pause.c + # ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/LcrcConnectMock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/grpc_client_mock.cc + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_BINARY_DIR}/json/container_path_stat.c + ${CMAKE_BINARY_DIR}/json/timestamp.c + pause_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/http + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/extend + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client/grpc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/cmd/isula/extend/pause/pause_llt.cc b/test/cmd/isula/extend/pause/pause_llt.cc new file mode 100644 index 0000000..4c2fecb --- /dev/null +++ b/test/cmd/isula/extend/pause/pause_llt.cc @@ -0,0 +1,84 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-14 + * Description: provide pause unit test + ******************************************************************************/ +#include "pause.h" +#include +#include +#include +#include +#include +#include "grpc_client_mock.h" +#include "utils.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class ContainerPauseUnitTest : public testing::Test { +public: + void SetUp() override + { + GrpcClient_SetMock(&m_grpcClient); + ::testing::Mock::AllowLeak(&m_grpcClient); + } + void TearDown() override + { + GrpcClient_SetMock(nullptr); + } + + NiceMock m_grpcClient; +}; +int ContainerPause(const struct isula_pause_request *request, + struct isula_pause_response *response, void *arg) +{ + (void)request; + (void)arg; + response->cc = 0; + response->server_errono = 0; + response->errmsg = nullptr; + return 0; +} + +int invokeGrpcOpsInit(isula_connect_ops *ops) +{ + if (ops == nullptr) { + return -1; + } + ops->container.pause = &ContainerPause; + return 0; +} + +TEST_F(ContainerPauseUnitTest, test_cmd_pause_main) +{ + const char *argv[] = {"isula", "pause", "2e05a97d"}; + const char *argv_failure[] = {"isula", "pause", "-x"}; + + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_pause_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_pause_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), + testing::ExitedWithCode(125), "Unkown flag found"); + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); +} + diff --git a/test/cmd/isula/extend/resume/CMakeLists.txt b/test/cmd/isula/extend/resume/CMakeLists.txt new file mode 100644 index 0000000..89dbc3f --- /dev/null +++ b/test/cmd/isula/extend/resume/CMakeLists.txt @@ -0,0 +1,56 @@ +project(iSulad_LLT) + +SET(EXE resume_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/commander.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisula.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/types_def.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/container_def.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/error.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client/isula_connect.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/extend/resume.c + # ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/LcrcConnectMock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/grpc_client_mock.cc + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_BINARY_DIR}/json/container_path_stat.c + ${CMAKE_BINARY_DIR}/json/timestamp.c + resume_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/http + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/extend + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client/grpc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) + diff --git a/test/cmd/isula/extend/resume/resume_llt.cc b/test/cmd/isula/extend/resume/resume_llt.cc new file mode 100644 index 0000000..781e460 --- /dev/null +++ b/test/cmd/isula/extend/resume/resume_llt.cc @@ -0,0 +1,84 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide unpause unit test + ******************************************************************************/ +#include "resume.h" +#include +#include +#include +#include +#include +#include "grpc_client_mock.h" +#include "utils.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class ContainerResumeUnitTest : public testing::Test { +public: + void SetUp() override + { + GrpcClient_SetMock(&m_grpcClient); + ::testing::Mock::AllowLeak(&m_grpcClient); + } + void TearDown() override + { + GrpcClient_SetMock(nullptr); + } + + NiceMock m_grpcClient; +}; +int ContainerResume(const struct isula_resume_request *request, + struct isula_resume_response *response, void *arg) +{ + (void)request; + (void)arg; + response->cc = 0; + response->server_errono = 0; + response->errmsg = nullptr; + return 0; +} + +int invokeGrpcOpsInit(isula_connect_ops *ops) +{ + if (ops == nullptr) { + return -1; + } + ops->container.resume = &ContainerResume; + return 0; +} + +TEST_F(ContainerResumeUnitTest, test_cmd_resume_main) +{ + const char *argv[] = {"isula", "unpause", "2e05a97d7cee"}; + const char *argv_failure[] = {"isula", "unpause", "-x"}; + + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_resume_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_resume_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), + testing::ExitedWithCode(125), "Unkown flag found"); + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); +} + diff --git a/test/cmd/isula/infomation/CMakeLists.txt b/test/cmd/isula/infomation/CMakeLists.txt new file mode 100644 index 0000000..80e0fb7 --- /dev/null +++ b/test/cmd/isula/infomation/CMakeLists.txt @@ -0,0 +1,4 @@ +project(iSulad_LLT) + +add_subdirectory(ps) +add_subdirectory(info) diff --git a/test/cmd/isula/infomation/info/CMakeLists.txt b/test/cmd/isula/infomation/info/CMakeLists.txt new file mode 100644 index 0000000..bb93fb2 --- /dev/null +++ b/test/cmd/isula/infomation/info/CMakeLists.txt @@ -0,0 +1,55 @@ +project(iSulad_LLT) + +SET(EXE info_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/commander.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisula.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/types_def.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/container_def.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/error.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client/isula_connect.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/information/info.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/grpc_client_mock.cc + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_BINARY_DIR}/json/container_path_stat.c + ${CMAKE_BINARY_DIR}/json/timestamp.c + info_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/http + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/information + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client/grpc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/cmd/isula/infomation/info/info_llt.cc b/test/cmd/isula/infomation/info/info_llt.cc new file mode 100644 index 0000000..b4a6b18 --- /dev/null +++ b/test/cmd/isula/infomation/info/info_llt.cc @@ -0,0 +1,158 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wangfengtu + * Create: 2020-02-20 + * Description: provide info mock + ******************************************************************************/ +#include "info.h" +#include +#include +#include +#include +#include +#include "grpc_client_mock.h" +#include "utils.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class InfoUnitTest : public testing::Test { +public: + void SetUp() override + { + GrpcClient_SetMock(&m_grpcClient); + ::testing::Mock::AllowLeak(&m_grpcClient); + } + void TearDown() override + { + GrpcClient_SetMock(nullptr); + } + + NiceMock m_grpcClient; +}; + +int Info(const struct isula_info_request *request, + struct isula_info_response *response, void *arg) +{ + const char *driver_status = "Pool Name: isula-thinpool\n" + "Pool Blocksize: 524.3kB\n" + "Base Device Size: 10.74GB\n" + "Backing Filesystem: ext4\n" + "Data file: \n" + "Metadata file: \n" + "Data Space Used: 536.3MB\n" + "Data Space Total: 30.6GB\n" + "Data Space Available: 30.06GB\n" + "Metadata Space Used: 17.32MB\n" + "Metadata Space Total: 318.8MB\n" + "Metadata Space Available: 301.4MB\n" + "Thin Pool Minimum Free Space: 3.06GB\n" + "Udev Sync Supported: true\n" + "Deferred Removal Enabled: true\n" + "Deferred Deletion Enabled: true\n" + "Deferred Deleted Device Count: 0\n" + "Library Version: 1.02.150 (2018-08-01)\n" + "Semaphore Set Used: 0\n" + "Semaphore Set Total: 32000\n"; + + response->driver_name = util_strdup_s("devicemapper"); + response->driver_status = util_strdup_s(driver_status); + response->version = util_strdup_s("1.1.11"); + response->kversion = util_strdup_s("4.19.36-vhulk1904.3.1.h226.eulerosv2r8.aarch64"); + response->os_type = util_strdup_s("Linux"); + response->architecture = util_strdup_s("aarch64"); + response->nodename = NULL; + response->operating_system = util_strdup_s("EulerOS 2.0 (SP8)"); + response->cgroup_driver = util_strdup_s("cgroupfs"); + response->logging_driver = util_strdup_s("json-file"); + response->huge_page_size = util_strdup_s("2MB"); + response->isulad_root_dir = util_strdup_s("/var/lib/isulad"); + response->http_proxy = NULL; + response->https_proxy = NULL; + response->no_proxy = NULL; + response->errmsg = NULL; + + return 0; +} + +int invokeGrpcOpsInit(isula_connect_ops *ops) +{ + if (ops == nullptr) { + return -1; + } + ops->container.info = &Info; + return 0; +} + +TEST_F(InfoUnitTest, test_cmd_info_main_all) +{ + const char *argv[] = {"isula", "info"}; + const char *argv_failure[] = {"isula", "info", "-k"}; + isula_connect_ops ops; + const char *driver_status = " Pool Name: isula-thinpool\n" + " Pool Blocksize: 524.3kB\n" + " Base Device Size: 10.74GB\n" + " Backing Filesystem: ext4\n" + " Data file: \n" + " Metadata file: \n" + " Data Space Used: 536.3MB\n" + " Data Space Total: 30.6GB\n" + " Data Space Available: 30.06GB\n" + " Metadata Space Used: 17.32MB\n" + " Metadata Space Total: 318.8MB\n" + " Metadata Space Available: 301.4MB\n" + " Thin Pool Minimum Free Space: 3.06GB\n" + " Udev Sync Supported: true\n" + " Deferred Removal Enabled: true\n" + " Deferred Deletion Enabled: true\n" + " Deferred Deleted Device Count: 0\n" + " Library Version: 1.02.150 (2018-08-01)\n" + " Semaphore Set Used: 0\n" + " Semaphore Set Total: 32000\n"; + + ops.container.info = &Info; + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)) + .WillOnce(Return(-1)) + .WillOnce(DoAll(SetArgPointee<0>(ByRef(ops)), Return(0))); + ASSERT_EQ(connect_client_ops_init(), -1); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_info_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + + testing::internal::CaptureStdout(); + + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_info_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_info_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), + testing::ExitedWithCode(125), "Unkown flag found"); + + std::string output = testing::internal::GetCapturedStdout(); + if (output.find("devicemapper") == std::string::npos) { + FAIL() << "isula info should contain devicemapper"; + } + if (output.find(driver_status) == std::string::npos) { + FAIL() << "isula info should contain driver status"; + } + + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); +} diff --git a/test/cmd/isula/infomation/ps/CMakeLists.txt b/test/cmd/isula/infomation/ps/CMakeLists.txt new file mode 100644 index 0000000..429cf20 --- /dev/null +++ b/test/cmd/isula/infomation/ps/CMakeLists.txt @@ -0,0 +1,54 @@ +project(iSulad_LLT) + +SET(EXE ps_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/commander.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisula.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/types_def.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/container_def.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/error.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client/isula_connect.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/information/ps.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/grpc_client_mock.cc + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_BINARY_DIR}/json/container_path_stat.c + ${CMAKE_BINARY_DIR}/json/timestamp.c + ps_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/http + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/information + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/connect/client/grpc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/cmd/isula/infomation/ps/ps_llt.cc b/test/cmd/isula/infomation/ps/ps_llt.cc new file mode 100644 index 0000000..e5e863b --- /dev/null +++ b/test/cmd/isula/infomation/ps/ps_llt.cc @@ -0,0 +1,224 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. + * Description: ps llt + * Author: wujing + * Create: 2019-12-19 + */ +#include "ps.h" +#include +#include +#include +#include +#include +#include "grpc_client_mock.h" +#include "utils.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class ContainerListUnitTest : public testing::Test { +public: + void SetUp() override + { + GrpcClient_SetMock(&m_grpcClient); + ::testing::Mock::AllowLeak(&m_grpcClient); + } + void TearDown() override + { + GrpcClient_SetMock(nullptr); + } + + NiceMock m_grpcClient; +}; + +namespace { +unsigned generate_random_pid() +{ + constexpr int pid_start = 10000; + constexpr int pid_end = 10000; + static default_random_engine e(time(0)); + static uniform_int_distribution u(pid_start, pid_end); + return u(e); +} + +long long generate_random_created() +{ + // unix nanos: 2019-01-01T00:00:00.000000000+08:00 + constexpr int64_t start = 1546272000000000000ll; + // unix nanos: 2019-12-31T00:00:00.000000000+08:00 + constexpr int64_t end = 1577721600000000000ll; + + static default_random_engine e(time(0)); + static uniform_int_distribution u(start, end); + return u(e); +} + +string generate_random_string(int length) +{ + static string chset = "abcdefghijklmnopqrstuvwxyz1234567890"; + string result; + result.resize(length); + + srand(time(NULL)); + for (int i = 0; i < length; i++) { + static default_random_engine e(time(0)); + static uniform_int_distribution u(0, chset.size() - 1); + result[i] = chset[u(e) % chset.length()]; + } + return result; +} + +int set_container_summary(struct isula_list_response *response, int index) +{ + constexpr int id_len = 64; + constexpr int name_len = 8; + + response->container_summary[index] = (struct isula_container_summary_info *)util_common_calloc_s( + sizeof(struct isula_container_summary_info)); + if (response->container_summary[index] == nullptr) { + return -1; + } + response->container_summary[index]->id = util_strdup_s(generate_random_string(id_len).c_str()); + response->container_summary[index]->name = util_strdup_s(generate_random_string(name_len).c_str()); + response->container_summary[index]->runtime = util_strdup_s("lcr"); + response->container_summary[index]->pid = generate_random_pid(); + response->container_summary[index]->status = (Container_Status)CONTAINER_STATUS_RUNNING; + response->container_summary[index]->image = util_strdup_s("busybox:latest"); + response->container_summary[index]->command = util_strdup_s("/bin/sh"); + response->container_summary[index]->startat = util_strdup_s("2019-12-31T23:55:50.867369507+08:00"); + response->container_summary[index]->finishat = util_strdup_s("2020-01-01T23:55:50.867369507+08:00"); + response->container_summary[index]->exit_code = 0; + response->container_summary[index]->restart_count = 0; + response->container_summary[index]->created = generate_random_created(); + response->container_summary[index]->health_state = util_strdup_s("(healthy)"); + response->container_num++; + + return 0; +} +} // namespace + +int ContainerList(const struct isula_list_request *request, + struct isula_list_response *response, void *arg) +{ + (void)request; + (void)arg; + constexpr int container_cnt = 5; + response->cc = 0; + response->server_errono = 0; + response->errmsg = nullptr; + response->container_summary = (struct isula_container_summary_info **)util_common_calloc_s( + sizeof(struct isula_container_summary_info *) * container_cnt); + if (response->container_summary == nullptr) { + return -1; + } + for (size_t i {}; i < container_cnt; ++i) { + if (set_container_summary(response, i)) { + return -1; + } + } + + return 0; +} + +int invokeGrpcOpsInit(isula_connect_ops *ops) +{ + if (ops == nullptr) { + return -1; + } + ops->container.list = &ContainerList; + return 0; +} + +TEST_F(ContainerListUnitTest, test_cmd_list_main_all) +{ + const char *argv[] = {"isula", "ps", "-a"}; + const char *argv_failure[] = {"isula", "ps", "-k"}; + isula_connect_ops ops; + + ops.container.list = &ContainerList; + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)) + .WillOnce(Return(-1)) + .WillOnce(DoAll(SetArgPointee<0>(ByRef(ops)), Return(0))); + ASSERT_EQ(connect_client_ops_init(), -1); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_list_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), + testing::ExitedWithCode(125), "Unkown flag found"); + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); +} + +TEST_F(ContainerListUnitTest, test_cmd_list_main_format) +{ + const char *argv[] = { + "isula", "ps", "-a", "--format", "\"table XXX{{.ID}}AAA{{.Image}}" + " {{.Status}} {{.Pid}} {{.Command}} {{.Created}} {{.Ports}} {{.ExitCode}} " + "{{.RestartCount}} {{.StartAt}} {{.FinishAt}} {{.Runtime}} \t{{.Names}} \n{{.State}}\"" + }; + const char *argv_failure[] = {"isula", "ps", "--format", "\"{{.ID}} {{.XXX}}"}; + + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_list_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), + testing::ExitedWithCode(1), "not support the field"); + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); +} + +TEST_F(ContainerListUnitTest, test_cmd_list_main_notrunc) +{ + const char *argv[] = {"isula", "ps", "-q", "--no-trunc"}; + testing::internal::CaptureStdout(); + + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + std::string output = testing::internal::GetCapturedStdout(); + if (output.find("CONTAINER ID") != std::string::npos) { + ADD_FAILURE() << "the output of command('isula ps -q --no-trunc') should not include table headers"; + } + std::cout << "Gtest Captured Stdout:" << std::endl << output; + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); +} + +TEST_F(ContainerListUnitTest, test_cmd_list_main_debug) +{ + const char *argv[] = {"isula", "ps", "-a", "-D"}; + testing::internal::CaptureStdout(); + + EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); + ASSERT_EQ(connect_client_ops_init(), 0); + EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + std::string output = testing::internal::GetCapturedStdout(); + std::vector tableItems {"CONTAINER ID", "IMAGE", "COMMAND", "CREATED", "STATUS", "PORTS", "NAMES"}; + for (const auto &elem : tableItems) { + if (output.find(elem) == std::string::npos) { + ADD_FAILURE() << "container list info should include " << elem; + } + } + if (output.find("healthy") == std::string::npos) { + FAIL() << "container list info should include healthy"; + } + std::cout << "Gtest Captured Stdout:" << std::endl << output; + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); + SUCCEED() << "test isula ps --debug success"; +} + diff --git a/test/cmd/isulad-shim/CMakeLists.txt b/test/cmd/isulad-shim/CMakeLists.txt new file mode 100644 index 0000000..8757c7e --- /dev/null +++ b/test/cmd/isulad-shim/CMakeLists.txt @@ -0,0 +1,22 @@ +project(iSulad_LLT) + +SET(EXE isulad-shim_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad-shim/process.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad-shim/common.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src/read_file.c + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_BINARY_DIR}/json/shim_client_process_state.c + isulad-shim_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad-shim + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src/ + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lyajl) diff --git a/test/cmd/isulad-shim/isulad-shim_llt.cc b/test/cmd/isulad-shim/isulad-shim_llt.cc new file mode 100644 index 0000000..6406291 --- /dev/null +++ b/test/cmd/isulad-shim/isulad-shim_llt.cc @@ -0,0 +1,122 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * Description: isulad-shim llt + * Author: leizhongkai + * Create: 2020-02-25 + */ +#include +#include +#include +#include +#include +#include + +#include "process.h" +#include "common.h" + +int g_log_fd = -1; + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class IsuladShimUnitTest : public testing::Test { +public: + void SetUp() override + { + } + void TearDown() override + { + } +}; + +TEST_F(IsuladShimUnitTest, test_new_process) +{ + string id = "aaaabbbbccccdddd"; + string bundle = "/home/isulad/bundle"; + string runtime = "kata-runtime"; + + process_t *p = new_process((char*)id.c_str(), (char*)bundle.c_str(), (char*)runtime.c_str()); + ASSERT_TRUE(p == NULL); +} + +TEST_F(IsuladShimUnitTest, test_open_no_inherit) +{ + string exist_file = "/tmp/test_open_no_inherit_exist"; + string non_file = "/tmp/test_open_no_inherit_non"; + int fd_exist = -1; + + fd_exist = open_no_inherit(exist_file.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0640); + EXPECT_GT(fd_exist, 0); + EXPECT_EQ(open_no_inherit(non_file.c_str(), O_WRONLY, -1), -1); + + close(fd_exist); + unlink(exist_file.c_str()); +} + +TEST_F(IsuladShimUnitTest, test_read_write_nointr) +{ + char buf[32] = { 0 }; + string test_file = "/tmp/test_read_nointr"; + string test_string = "hello"; + int fd_wr = -1; + int fd_rd = -1; + int nwrite = -1; + int nread = -1; + + EXPECT_EQ(read_nointr(-1, NULL, 32), -1); + EXPECT_EQ(read_nointr(0, NULL, 32), -1); + EXPECT_EQ(read_nointr(1, NULL, 32), -1); + + fd_wr = open_no_inherit(test_file.c_str(), O_CREAT | O_RDWR | O_APPEND | O_SYNC, 0640); + EXPECT_GT(fd_wr, 0); + nwrite = write_nointr(fd_wr, test_string.c_str(), 5); + EXPECT_EQ(nwrite, 5); + fd_rd = open(test_file.c_str(), O_RDONLY); + nread = read_nointr(fd_rd, buf, 32); + EXPECT_EQ(nread, 5); + + close(fd_wr); + close(fd_rd); + unlink(test_file.c_str()); +} + +TEST_F(IsuladShimUnitTest, test_file_exist) +{ + string exist_file = "/tmp/test_exist_exist"; + string non_file = "/tmp/test_exist_non"; + int fd_exist = -1; + + fd_exist = open_no_inherit(exist_file.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0640); + EXPECT_GT(fd_exist, 0); + EXPECT_TRUE(file_exists(exist_file.c_str())); + EXPECT_FALSE(file_exists(non_file.c_str())); + + close(fd_exist); + unlink(exist_file.c_str()); +} + + +TEST_F(IsuladShimUnitTest, test_combined_output) +{ + string exist_cmd = "ls"; + string non_cmd = "aaa"; + const char *params[MAX_RUNTIME_ARGS] = { NULL }; + char output[BUFSIZ] = { 0 }; + int output_len = BUFSIZ; + + params[0] = exist_cmd.c_str(); + EXPECT_EQ(cmd_combined_output(exist_cmd.c_str(), params, output, &output_len), 0); + + params[0] = non_cmd.c_str(); + EXPECT_EQ(cmd_combined_output(non_cmd.c_str(), params, output, &output_len), -1); +} diff --git a/test/cutils/utils_convert/utils_convert_llt.cc b/test/cutils/utils_convert/utils_convert_llt.cc index 0ad48f8..d7c944d 100644 --- a/test/cutils/utils_convert/utils_convert_llt.cc +++ b/test/cutils/utils_convert/utils_convert_llt.cc @@ -185,7 +185,7 @@ TEST(utils_convert, test_util_safe_strtod) TEST(utils_convert, test_util_str_to_bool) { int ret; - bool converted; + bool converted = false; ret = util_str_to_bool("1", &converted); ASSERT_EQ(ret, 0); ASSERT_TRUE(converted); diff --git a/test/cutils/utils_string/utils_string_llt.cc b/test/cutils/utils_string/utils_string_llt.cc index 04210bd..36dbcf9 100644 --- a/test/cutils/utils_string/utils_string_llt.cc +++ b/test/cutils/utils_string/utils_string_llt.cc @@ -757,3 +757,52 @@ TEST(utils_string_llt, test_dup_array_of_strings) MOCK_CLEAR(calloc); } +TEST(utils_string_llt, test_parse_percent_string) +{ + long converted = 0; + int ret = 0; + const char *correct1 = "10%"; + const char *correct2 = "0%"; + const char *correct3 = "100%"; + const char *correct4 = "99%"; + const char *wrong1 = "50"; + const char *wrong2 = "-10%"; + const char *wrong3 = "101%"; + const char *wrong4 = "a10%"; + const char *wrong5 = "10%k"; + const char *wrong6 = "1x0%"; + + ret = util_parse_percent_string(correct1, &converted); + ASSERT_EQ(ret, 0); + ASSERT_EQ(converted, 10); + + ret = util_parse_percent_string(correct2, &converted); + ASSERT_EQ(ret, 0); + ASSERT_EQ(converted, 0); + + ret = util_parse_percent_string(correct3, &converted); + ASSERT_EQ(ret, 0); + ASSERT_EQ(converted, 100); + + ret = util_parse_percent_string(correct4, &converted); + ASSERT_EQ(ret, 0); + ASSERT_EQ(converted, 99); + + ret = util_parse_percent_string(wrong1, &converted); + ASSERT_NE(ret, 0); + + ret = util_parse_percent_string(wrong2, &converted); + ASSERT_NE(ret, 0); + + ret = util_parse_percent_string(wrong3, &converted); + ASSERT_NE(ret, 0); + + ret = util_parse_percent_string(wrong4, &converted); + ASSERT_NE(ret, 0); + + ret = util_parse_percent_string(wrong5, &converted); + ASSERT_NE(ret, 0); + + ret = util_parse_percent_string(wrong6, &converted); + ASSERT_NE(ret, 0); +} diff --git a/test/image/oci/oci_config_merge/CMakeLists.txt b/test/image/oci/oci_config_merge/CMakeLists.txt index 14d964a..1dee365 100644 --- a/test/image/oci/oci_config_merge/CMakeLists.txt +++ b/test/image/oci/oci_config_merge/CMakeLists.txt @@ -11,11 +11,11 @@ add_executable(${EXE} ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_string.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_convert.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/util_atomic.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/log.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/sha256/sha256.c ${CMAKE_BINARY_DIR}/json/json_common.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/path.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/spec/specs_mount.c ${CMAKE_BINARY_DIR}/json/host_config.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/spec/specs_extend.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libisulad.c @@ -31,6 +31,11 @@ add_executable(${EXE} ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/json/schema/src/read_file.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad/arguments.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/image/oci/oci_llt_common.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/containers_store_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/namespace_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/container_unix_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/spec/specs_mount.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/selinux_label_mock.cc ${CMAKE_BINARY_DIR}/json/imagetool_image.c ${CMAKE_BINARY_DIR}/json/oci_image_spec.c oci_config_merge_llt.cc) @@ -41,8 +46,12 @@ target_include_directories(${EXE} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/image/oci ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/engines ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/json ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/spec + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/events ${CMAKE_BINARY_DIR}/json ${CMAKE_BINARY_DIR}/conf ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/sha256 @@ -52,7 +61,8 @@ target_include_directories(${EXE} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/json/schema/src ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/console ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks ) set_target_properties(${EXE} PROPERTIES LINK_FLAGS "-Wl,--wrap,util_common_calloc_s -Wl,--wrap,util_smart_calloc_s -Wl,--wrap,merge_env") -target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} -lyajl -lz) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/image/oci/oci_config_merge/oci_runtime_spec.json b/test/image/oci/oci_config_merge/oci_runtime_spec.json index 50726e6..7963757 100644 --- a/test/image/oci/oci_config_merge/oci_runtime_spec.json +++ b/test/image/oci/oci_config_merge/oci_runtime_spec.json @@ -1,5 +1,5 @@ { - "ociVersion": "1.0.0-rc5-dev", + "ociVersion": "1.0.1", "hooks": { }, diff --git a/test/mocks/collector_mock.cc b/test/mocks/collector_mock.cc new file mode 100644 index 0000000..169f236 --- /dev/null +++ b/test/mocks/collector_mock.cc @@ -0,0 +1,52 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide collector mock + ******************************************************************************/ + +#include "collector_mock.h" + +namespace { +MockCollector *g_collector_mock = NULL; +} + +void MockCollector_SetMock(MockCollector *mock) +{ + g_collector_mock = mock; +} + +int events_subscribe(const char *name, const types_timestamp_t *since, const types_timestamp_t *until, + const stream_func_wrapper *stream) +{ + if (g_collector_mock != nullptr) { + return g_collector_mock->EventsSubscribe(name, since, until, stream); + } + return 0; +} + +int add_monitor_client(char *name, const types_timestamp_t *since, const types_timestamp_t *until, + const stream_func_wrapper *stream) +{ + if (g_collector_mock != nullptr) { + return g_collector_mock->AddMonitorClient(name, since, until, stream); + } + return 0; +} + +int isulad_monitor_send_container_event(const char *name, runtime_state_t state, int pid, int exit_code, + const char *args, const char *extra_annations) +{ + if (g_collector_mock != nullptr) { + return g_collector_mock->IsuladMonitorSendContainerEvent(name, state, pid, exit_code, args, extra_annations); + } + return 0; +} diff --git a/test/mocks/collector_mock.h b/test/mocks/collector_mock.h new file mode 100644 index 0000000..a7a0c4c --- /dev/null +++ b/test/mocks/collector_mock.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide collector mock + ******************************************************************************/ + +#ifndef COLLECTOR_MOCK_H_ +#define COLLECTOR_MOCK_H_ + +#include +#include "collector.h" + +class MockCollector { +public: + MOCK_METHOD4(EventsSubscribe, int(const char *name, const types_timestamp_t *since, const types_timestamp_t *until, + const stream_func_wrapper *stream)); + MOCK_METHOD4(AddMonitorClient, int(const char *name, const types_timestamp_t *since, const types_timestamp_t *until, + const stream_func_wrapper *stream)); + MOCK_METHOD6(IsuladMonitorSendContainerEvent, int(const char *name, runtime_state_t state, int pid, int exit_code, + const char *args, const char *extra_annations)); +}; + +void MockCollector_SetMock(MockCollector* mock); + +#endif diff --git a/test/mocks/container_state_mock.cc b/test/mocks/container_state_mock.cc new file mode 100644 index 0000000..0e88d4e --- /dev/null +++ b/test/mocks/container_state_mock.cc @@ -0,0 +1,86 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide container_state mock + ******************************************************************************/ + +#include "container_state_mock.h" + +namespace { +MockContainerState *g_container_state_mock = NULL; +} + +void MockContainerState_SetMock(MockContainerState *mock) +{ + g_container_state_mock = mock; +} + +bool is_running(container_state_t *s) +{ + if (g_container_state_mock != nullptr) { + return g_container_state_mock->IsRunning(s); + } + return true; +} + +bool is_restarting(container_state_t *s) +{ + if (g_container_state_mock != nullptr) { + return g_container_state_mock->IsRestarting(s); + } + return false; +} + +bool is_dead(container_state_t *s) +{ + if (g_container_state_mock != nullptr) { + return g_container_state_mock->IsDead(s); + } + return true; +} + +void container_state_set_error(container_state_t *s, const char *err) +{ + if (g_container_state_mock != nullptr) { + return g_container_state_mock->ContainerStateSetError(s, err); + } +} + +bool is_paused(container_state_t *s) +{ + if (g_container_state_mock != nullptr) { + return g_container_state_mock->IsPaused(s); + } + return true; +} + +void state_reset_paused(container_state_t *s) +{ + if (g_container_state_mock != nullptr) { + return g_container_state_mock->StateResetPaused(s); + } +} + +void state_set_paused(container_state_t *s) +{ + if (g_container_state_mock != nullptr) { + return g_container_state_mock->StateSetPaused(s); + } +} + +bool is_removal_in_progress(container_state_t *s) +{ + if (g_container_state_mock != nullptr) { + return g_container_state_mock->IsRemovalInProgress(s); + } + return true; +} diff --git a/test/mocks/container_state_mock.h b/test/mocks/container_state_mock.h new file mode 100644 index 0000000..f64b5bf --- /dev/null +++ b/test/mocks/container_state_mock.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide container_state mock + ******************************************************************************/ + +#ifndef CONTAINER_STATE_MOCK_H_ +#define CONTAINER_STATE_MOCK_H_ + +#include +#include "container_state.h" + +class MockContainerState { +public: + MOCK_METHOD1(IsRunning, bool(container_state_t *s)); + MOCK_METHOD1(IsPaused, bool(container_state_t *s)); + MOCK_METHOD1(IsRestarting, bool(container_state_t *s)); + MOCK_METHOD1(IsDead, bool(container_state_t *s)); + MOCK_METHOD1(StateResetPaused, void(container_state_t *s)); + MOCK_METHOD2(ContainerStateSetError, void(container_state_t *s, const char *err)); + MOCK_METHOD1(StateSetPaused, void(container_state_t *s)); + MOCK_METHOD1(IsRemovalInProgress, bool(container_state_t *s)); +}; + +void MockContainerState_SetMock(MockContainerState* mock); + +#endif diff --git a/test/mocks/container_unix_mock.cc b/test/mocks/container_unix_mock.cc new file mode 100644 index 0000000..cd8374a --- /dev/null +++ b/test/mocks/container_unix_mock.cc @@ -0,0 +1,78 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: lifeng + * Create: 2020-02-14 + * Description: provide container unix mock + ******************************************************************************/ + +#include "container_unix_mock.h" + +namespace { +MockContainerUnix *g_container_unix_mock = NULL; +} + +void MockContainerUnix_SetMock(MockContainerUnix* mock) +{ + g_container_unix_mock = mock; +} + + +/* container unref */ +void container_unref(container_t *cont) +{ + if (g_container_unix_mock != nullptr) { + return g_container_unix_mock->ContainerUnref(cont); + } + return; +} + +bool has_mount_for(container_t *cont, const char *mpath) +{ + if (g_container_unix_mock != nullptr) { + return g_container_unix_mock->HasMountFor(cont, mpath); + } + return false; +} + +int container_read_proc(uint32_t pid, container_pid_t *pid_info) +{ + return 0; +} + +int container_to_disk(const container_t *cont) +{ + if (g_container_unix_mock != nullptr) { + return g_container_unix_mock->ContainerToDisk(cont); + } + return 0; +} + +void container_unlock(container_t *cont) +{ + if (g_container_unix_mock != nullptr) { + return g_container_unix_mock->ContainerUnlock(cont); + } +} + +void container_lock(container_t *cont) +{ + if (g_container_unix_mock != nullptr) { + return g_container_unix_mock->ContainerLock(cont); + } +} + +void container_update_restart_manager(container_t *cont, const host_config_restart_policy *policy) +{ + if (g_container_unix_mock != nullptr) { + return g_container_unix_mock->ContainerUpdateRestartManager(cont, policy); + } +} + diff --git a/test/mocks/container_unix_mock.h b/test/mocks/container_unix_mock.h new file mode 100644 index 0000000..4197706 --- /dev/null +++ b/test/mocks/container_unix_mock.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: lifeng + * Create: 2020-02-14 + * Description: provide container unix mock + ******************************************************************************/ + +#ifndef CONTAINER_UNIX_MOCK_H_ +#define CONTAINER_UNIX_MOCK_H_ + +#include +#include "container_unix.h" + +class MockContainerUnix { +public: + virtual ~MockContainerUnix() = default; + MOCK_METHOD2(HasMountFor, bool(container_t *cont, const char *mpath)); + MOCK_METHOD1(ContainerToDisk, int(const container_t *cont)); + MOCK_METHOD1(ContainerUnlock, void(const container_t *cont)); + MOCK_METHOD1(ContainerLock, void(const container_t *cont)); + MOCK_METHOD1(ContainerUnref, void(container_t *cont)); + MOCK_METHOD2(ContainerUpdateRestartManager, void(container_t *cont, const host_config_restart_policy *policy)); +}; + +void MockContainerUnix_SetMock(MockContainerUnix* mock); + +#endif // CONTAINER_UNIX_MOCK_H_ diff --git a/test/mocks/containers_gc_mock.cc b/test/mocks/containers_gc_mock.cc new file mode 100644 index 0000000..74b8039 --- /dev/null +++ b/test/mocks/containers_gc_mock.cc @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide containers_gc mock + ******************************************************************************/ + +#include "containers_gc_mock.h" + +namespace { +MockContainersGc *g_containers_gc_mock = NULL; +} + +void MockContainersGc_SetMock(MockContainersGc *mock) +{ + g_containers_gc_mock = mock; +} + +bool gc_is_gc_progress(const char *id) +{ + if (g_containers_gc_mock != nullptr) { + return g_containers_gc_mock->GcIsGcProgress(id); + } + return true; +} diff --git a/test/mocks/containers_gc_mock.h b/test/mocks/containers_gc_mock.h new file mode 100644 index 0000000..c1ea541 --- /dev/null +++ b/test/mocks/containers_gc_mock.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide containers_gc mock + ******************************************************************************/ + +#ifndef CONTAINERS_GC_MOCK_H_ +#define CONTAINERS_GC_MOCK_H_ + +#include +#include "containers_gc.h" + +class MockContainersGc { +public: + MOCK_METHOD1(GcIsGcProgress, bool(const char *id)); +}; + +void MockContainersGc_SetMock(MockContainersGc* mock); + +#endif diff --git a/test/mocks/containers_store_mock.cc b/test/mocks/containers_store_mock.cc new file mode 100644 index 0000000..65022f5 --- /dev/null +++ b/test/mocks/containers_store_mock.cc @@ -0,0 +1,132 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide containers store mock + ******************************************************************************/ + +#include "containers_store_mock.h" + +namespace { +MockContainersStore *g_containers_store_mock = NULL; +} + +void MockContainersStore_SetMock(MockContainersStore* mock) +{ + g_containers_store_mock = mock; +} + + +int containers_store_init(void) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->ContainersStoreInit(); + } + return -1; +} + +bool containers_store_add(const char *id, container_t *cont) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->ContainersStoreAdd(id, cont); + } + return false; +} + +container_t *containers_store_get(const char *id_or_name) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->ContainersStoreGet(id_or_name); + } + return nullptr; +} + +container_t *containers_store_get_by_prefix(const char *prefix) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->ContainersStoreGetByPrefix(prefix); + } + return nullptr; +} + +bool containers_store_remove(const char *id) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->ContainersStoreRemove(id); + } + return false; +} + +int containers_store_list(container_t ***out, size_t *size) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->ContainersStoreList(out, size); + } + return -1; +} + +char **containers_store_list_ids(void) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->ContainersStoreListIds(); + } + return nullptr; +} + + +int name_index_init(void) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->NameIndexInit(); + } + return -1; +} + +bool name_index_remove(const char *name) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->NameIndexRemove(name); + } + return false; +} + +char *name_index_get(const char *name) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->NameIndexGet(name); + } + return nullptr; +} + + +bool name_index_add(const char *name, const char *id) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->NameIndexAdd(name, id); + } + return false; +} + +map_t *name_index_get_all(void) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->NameIndexGetAll(); + } + return nullptr; +} + +bool name_index_rename(const char *new_name, const char *old_name, const char *id) +{ + if (g_containers_store_mock != nullptr) { + return g_containers_store_mock->NameIndexRename(new_name, old_name, id); + } + return false; +} diff --git a/test/mocks/containers_store_mock.h b/test/mocks/containers_store_mock.h new file mode 100644 index 0000000..3d0f16b --- /dev/null +++ b/test/mocks/containers_store_mock.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide containers store mock + ******************************************************************************/ + +#ifndef CONTAINERS_STORE_MOCK_H_ +#define CONTAINERS_STORE_MOCK_H_ + +#include +#include "containers_store.h" + +class MockContainersStore { +public: + virtual ~MockContainersStore() = default; + MOCK_METHOD0(ContainersStoreInit, int(void)); + MOCK_METHOD2(ContainersStoreAdd, bool(const char *id, container_t *cont)); + MOCK_METHOD1(ContainersStoreGet, container_t *(const char *id_or_name)); + MOCK_METHOD1(ContainersStoreGetByPrefix, container_t *(const char *prefix)); + MOCK_METHOD1(ContainersStoreRemove, bool(const char *id)); + MOCK_METHOD2(ContainersStoreList, int(container_t ***out, size_t *size)); + MOCK_METHOD0(ContainersStoreListIds, char **(void)); + MOCK_METHOD0(NameIndexInit, int(void)); + MOCK_METHOD1(NameIndexRemove, bool(const char *name)); + MOCK_METHOD1(NameIndexGet, char *(const char *name)); + MOCK_METHOD2(NameIndexAdd, bool(const char *name, const char *id)); + MOCK_METHOD0(NameIndexGetAll, map_t * (void)); + MOCK_METHOD3(NameIndexRename, bool(const char *new_name, const char *old_name, const char *id)); +}; + +void MockContainersStore_SetMock(MockContainersStore* mock); + +#endif // CONTAINERS_STORE_MOCK_H_ \ No newline at end of file diff --git a/test/mocks/driver_mock.cc b/test/mocks/driver_mock.cc new file mode 100644 index 0000000..75f23ee --- /dev/null +++ b/test/mocks/driver_mock.cc @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide driver mock + ******************************************************************************/ + +#include "driver_mock.h" + +namespace { +MockDriver *g_driver_mock = NULL; +} + +void MockDriver_SetMock(MockDriver *mock) +{ + g_driver_mock = mock; +} diff --git a/test/mocks/driver_mock.h b/test/mocks/driver_mock.h new file mode 100644 index 0000000..856f853 --- /dev/null +++ b/test/mocks/driver_mock.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide driver mock + ******************************************************************************/ + +#ifndef DRIVER_MOCK_H_ +#define DRIVER_MOCK_H_ + +#include +#include "driver.h" + +class MockDriver { +}; + +void MockDriver_SetMock(MockDriver* mock); + +#endif diff --git a/test/mocks/driver_overlay2_mock.cc b/test/mocks/driver_overlay2_mock.cc new file mode 100644 index 0000000..8289dae --- /dev/null +++ b/test/mocks/driver_overlay2_mock.cc @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wangfengtu + * Create: 2020-02-19 + * Description: provide driver overlay2 mock + ******************************************************************************/ + +#include "driver_overlay2_mock.h" + +namespace { +MockDriverOverlay2 *g_driver_overlay2_mock = NULL; +} + +void MockDriverOverlay2_SetMock(MockDriverOverlay2* mock) +{ + g_driver_overlay2_mock = mock; +} + +int overlay2_init(struct graphdriver *driver) +{ + if (g_driver_overlay2_mock != nullptr) { + return g_driver_overlay2_mock->Overlay2Init(driver); + } + return -1; +} + +int overlay2_parse_options(struct graphdriver *driver, const char **options, size_t options_len) +{ + if (g_driver_overlay2_mock != nullptr) { + return g_driver_overlay2_mock->Overlay2ParseOptions(driver, options, options_len); + } + return -1; +} + +bool overlay2_is_quota_options(struct graphdriver *driver, const char *option) +{ + if (g_driver_overlay2_mock != nullptr) { + return g_driver_overlay2_mock->Overlay2IsQuotaOptions(driver, option); + } + return false; +} diff --git a/test/mocks/driver_overlay2_mock.h b/test/mocks/driver_overlay2_mock.h new file mode 100644 index 0000000..0653818 --- /dev/null +++ b/test/mocks/driver_overlay2_mock.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wangfengtu + * Create: 2020-02-19 + * Description: provide driver overlay2 mock + ******************************************************************************/ + +#ifndef DRIVER_OVERLAY2_MOCK_H_ +#define DRIVER_OVERLAY2_MOCK_H_ + +#include +#include "driver_overlay2.h" + +class MockDriverOverlay2 { +public: + virtual ~MockDriverOverlay2() = default; + MOCK_METHOD1(Overlay2Init, int(struct graphdriver *)); + MOCK_METHOD3(Overlay2ParseOptions, int(struct graphdriver *, const char **, size_t)); + MOCK_METHOD2(Overlay2IsQuotaOptions, bool(struct graphdriver *, const char *)); +}; + +void MockDriverOverlay2_SetMock(MockDriverOverlay2* mock); + +#endif // DRIVER_OVERLAY2_MOCK_H_ diff --git a/test/mocks/engine_mock.cc b/test/mocks/engine_mock.cc new file mode 100644 index 0000000..0e55f23 --- /dev/null +++ b/test/mocks/engine_mock.cc @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide namespace mock + ******************************************************************************/ + +#include "engine_mock.h" + +namespace { +MockEngine *g_engine_mock = NULL; +} + +void MockEngine_SetMock(MockEngine* mock) +{ + g_engine_mock = mock; +} + +struct engine_operation *engines_get_handler(const char *name) +{ + if (g_engine_mock != nullptr) { + return g_engine_mock->EngineGetHandler(name); + } + return nullptr; +} diff --git a/test/mocks/engine_mock.h b/test/mocks/engine_mock.h new file mode 100644 index 0000000..18e6d5e --- /dev/null +++ b/test/mocks/engine_mock.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide engine mock + ******************************************************************************/ + +#ifndef ENGINE_MOCK_H_ +#define ENGINE_MOCK_H_ + +#include +#include "engine.h" + +class MockEngine { +public: + virtual ~MockEngine() = default; + MOCK_METHOD1(EngineGetHandler, struct engine_operation * (const char *name)); +}; + +void MockEngine_SetMock(MockEngine* mock); + +#endif // ENGINE_MOCK_H_ diff --git a/test/mocks/grpc_client_mock.cc b/test/mocks/grpc_client_mock.cc new file mode 100644 index 0000000..a58f4e0 --- /dev/null +++ b/test/mocks/grpc_client_mock.cc @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2019-12-19 + * Description: provide grpc client mock + ******************************************************************************/ + +#include "grpc_client_mock.h" + +namespace { +MockGrpcClient *g_grpc_client_mock = NULL; +} + +void GrpcClient_SetMock(MockGrpcClient* mock) +{ + g_grpc_client_mock = mock; +} + +int grpc_ops_init(isula_connect_ops *ops) +{ + if (g_grpc_client_mock != nullptr) { + return g_grpc_client_mock->GrpcOpsInit(ops); + } + return 0; +} + diff --git a/test/mocks/grpc_client_mock.h b/test/mocks/grpc_client_mock.h new file mode 100644 index 0000000..3b988ab --- /dev/null +++ b/test/mocks/grpc_client_mock.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2019-12-19 + * Description: provide grpc client mock + ******************************************************************************/ + +#ifndef GRPC_CLIENT_MOCK_H_ +#define GRPC_CLIENT_MOCK_H_ + +#include +#include "grpc_client.h" + +class MockGrpcClient { +public: + virtual ~MockGrpcClient() = default; + MOCK_METHOD1(GrpcOpsInit, int(isula_connect_ops *ops)); +}; + +void GrpcClient_SetMock(MockGrpcClient* mock); + +#endif // GRPC_CLIENT_MOCK_H_ diff --git a/test/mocks/health_check_mock.cc b/test/mocks/health_check_mock.cc new file mode 100644 index 0000000..51d84fc --- /dev/null +++ b/test/mocks/health_check_mock.cc @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide health_check mock + ******************************************************************************/ + +#include "health_check_mock.h" + +namespace { +MockHealthCheck *g_health_check_mock = NULL; +} + +void MockHealthCheck_SetMock(MockHealthCheck *mock) +{ + g_health_check_mock = mock; +} + +void update_health_monitor(const char *container_id) +{ + if (g_health_check_mock != nullptr) { + return g_health_check_mock->UpdateHealthMonitor(container_id); + } + return; +} diff --git a/test/mocks/health_check_mock.h b/test/mocks/health_check_mock.h new file mode 100644 index 0000000..fce65af --- /dev/null +++ b/test/mocks/health_check_mock.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide health_check mock + ******************************************************************************/ + +#ifndef HEALTH_CHECK_MOCK_H_ +#define HEALTH_CHECK_MOCK_H_ + +#include +#include "health_check.h" + +class MockHealthCheck { +public: + MOCK_METHOD1(UpdateHealthMonitor, void(const char *container_id)); +}; + +void MockHealthCheck_SetMock(MockHealthCheck* mock); + +#endif diff --git a/test/mocks/image_mock.cc b/test/mocks/image_mock.cc new file mode 100644 index 0000000..7d1cb7f --- /dev/null +++ b/test/mocks/image_mock.cc @@ -0,0 +1,57 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wangfengtu + * Create: 2020-02-19 + * Description: provide image mock + ******************************************************************************/ + +#include "image_mock.h" + +namespace { +MockImage *g_image_mock = NULL; +} + +void MockImage_SetMock(MockImage* mock) +{ + g_image_mock = mock; +} + +int im_get_storage_status(const char *image_type, im_storage_status_response **response) +{ + if (g_image_mock != nullptr) { + return g_image_mock->ImGetStorageStatus(image_type, response); + } + return -1; +} + +void free_im_storage_status_response(im_storage_status_response *ptr) +{ + if (g_image_mock != nullptr) { + g_image_mock->FreeImStorageStatusResponse(ptr); + return; + } + return; +} + +int im_container_export(const im_export_request *request) +{ + if (g_image_mock != nullptr) { + return g_image_mock->ImContainerExport(request); + } + return 0; +} + +void free_im_export_request(im_export_request *ptr) +{ + if (g_image_mock != nullptr) { + return g_image_mock->FreeImExportRequest(ptr); + } +} diff --git a/test/mocks/image_mock.h b/test/mocks/image_mock.h new file mode 100644 index 0000000..7f97e2a --- /dev/null +++ b/test/mocks/image_mock.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wangfengtu + * Create: 2020-02-19 + * Description: provide image mock + ******************************************************************************/ + +#ifndef IMAGE_MOCK_H_ +#define IMAGE_MOCK_H_ + +#include +#include "image.h" + +class MockImage { +public: + virtual ~MockImage() = default; + MOCK_METHOD2(ImGetStorageStatus, int(const char *, im_storage_status_response **)); + MOCK_METHOD1(FreeImStorageStatusResponse, void(im_storage_status_response *)); + MOCK_METHOD1(ImContainerExport, int(const im_export_request *request)); + MOCK_METHOD1(FreeImExportRequest, void(im_export_request *ptr)); +}; + +void MockImage_SetMock(MockImage* mock); + +#endif // IMAGE_MOCK_H_ diff --git a/test/mocks/isulad_config_mock.cc b/test/mocks/isulad_config_mock.cc new file mode 100644 index 0000000..cdef765 --- /dev/null +++ b/test/mocks/isulad_config_mock.cc @@ -0,0 +1,130 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide namespace mock + ******************************************************************************/ + +#include "isulad_config_mock.h" + +namespace { +MockIsuladConf *g_isulad_conf_mock = NULL; +} + +void MockIsuladConf_SetMock(MockIsuladConf* mock) +{ + g_isulad_conf_mock = mock; +} + +char *conf_get_routine_rootdir(const char *runtime) +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->GetRuntimeDir(runtime); + } + return nullptr; +} + +int parse_log_opts(struct service_arguments *args, const char *key, const char *value) +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->ParseLogopts(args, key, value); + } + return -1; +} + +int conf_get_isulad_default_ulimit(host_config_ulimits_element ***ulimit) +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->GetUlimit(ulimit); + } + return -1; +} + +int conf_get_isulad_hooks(oci_runtime_spec_hooks **phooks) +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->GetHooks(phooks); + } + return -1; +} + +/* conf get isulad mount rootfs */ +char *conf_get_isulad_mount_rootfs() +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->GetMountrootfs(); + } + return nullptr; +} + +/* conf get isulad cgroup parent for containers */ +char *conf_get_isulad_cgroup_parent() +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->GetCgroupParent(); + } + return nullptr; +} + +char *conf_get_isulad_native_umask() +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->GetUmask(); + } + return nullptr; +} + +char *conf_get_graph_rootpath() +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->ConfGetGraphRootpath(); + } + return nullptr; +} + +char *conf_get_isulad_storage_driver() +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->ConfGetIsuladStorageDriver(); + } + return nullptr; +} + +int isulad_server_conf_rdlock() +{ + return 0; +} + +int isulad_server_conf_unlock() +{ + return 0; +} + +struct service_arguments *conf_get_server_conf() +{ + return NULL; +} + +int get_system_cpu_usage(uint64_t *val) +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->GetSystemCpuUsage(val); + } + return 0; +} + +char *conf_get_isulad_storage_driver_backing_fs() +{ + if (g_isulad_conf_mock != nullptr) { + return g_isulad_conf_mock->ConfGetIsuladStorageDriverBackingFs(); + } + return nullptr; +} diff --git a/test/mocks/isulad_config_mock.h b/test/mocks/isulad_config_mock.h new file mode 100644 index 0000000..1e1f408 --- /dev/null +++ b/test/mocks/isulad_config_mock.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide isulad config mock + ******************************************************************************/ + +#ifndef ISULAD_CONFIG_MOCK_H_ +#define ISULAD_CONFIG_MOCK_H_ + +#include +#include "isulad_config.h" + +class MockIsuladConf { +public: + virtual ~MockIsuladConf() = default; + MOCK_METHOD1(GetRuntimeDir, char *(const char *name)); + MOCK_METHOD3(ParseLogopts, int(struct service_arguments *args, const char *key, const char *value)); + MOCK_METHOD0(GetMountrootfs, char *(void)); + MOCK_METHOD1(GetHooks, int(oci_runtime_spec_hooks **phooks)); + MOCK_METHOD1(GetUlimit, int(host_config_ulimits_element ***ulimit)); + MOCK_METHOD0(GetCgroupParent, char *(void)); + MOCK_METHOD0(GetUmask, char *(void)); + MOCK_METHOD0(ConfGetGraphRootpath, char *(void)); + MOCK_METHOD0(ConfGetIsuladStorageDriver, char *(void)); + MOCK_METHOD1(GetSystemCpuUsage, int(uint64_t *val)); + MOCK_METHOD0(ConfGetIsuladStorageDriverBackingFs, char*()); + +}; + +void MockIsuladConf_SetMock(MockIsuladConf* mock); + +#endif // ISULAD_CONFIG_MOCK_H_ diff --git a/test/mocks/namespace_mock.cc b/test/mocks/namespace_mock.cc new file mode 100644 index 0000000..33041ff --- /dev/null +++ b/test/mocks/namespace_mock.cc @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide namespace mock + ******************************************************************************/ + +#include "namespace_mock.h" + +namespace { +MockNamespace *g_namespace_mock = NULL; +} + +void MockNamespace_SetMock(MockNamespace* mock) +{ + g_namespace_mock = mock; +} + +char *connected_container(const char *mode) +{ + if (g_namespace_mock != nullptr) { + return g_namespace_mock->ConnectedContainer(mode); + } + return nullptr; +} + +char *get_share_namespace_path(const char *type, const char *src_path) +{ + if (g_namespace_mock != nullptr) { + return g_namespace_mock->GetShareNamespacePath(type, src_path); + } + return nullptr; +} + +char *get_container_process_label(const char *path) +{ + if (g_namespace_mock != nullptr) { + return g_namespace_mock->GetContainerProcessLabel(path); + } + return nullptr; +} diff --git a/test/mocks/namespace_mock.h b/test/mocks/namespace_mock.h new file mode 100644 index 0000000..85f7c85 --- /dev/null +++ b/test/mocks/namespace_mock.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide namespace mock + ******************************************************************************/ + +#ifndef NAMESPACE_MOCK_H_ +#define NAMESPACE_MOCK_H_ + +#include +#include "namespace.h" + +class MockNamespace { +public: + virtual ~MockNamespace() = default; + MOCK_METHOD1(ConnectedContainer, char *(const char *mode)); + MOCK_METHOD2(GetShareNamespacePath, char *(const char *type, const char *src_path)); + MOCK_METHOD1(GetContainerProcessLabel, char *(const char *path)); +}; + +void MockNamespace_SetMock(MockNamespace* mock); + +#endif // NAMESPACE_MOCK_H_ diff --git a/test/mocks/restartmanager_mock.cc b/test/mocks/restartmanager_mock.cc new file mode 100644 index 0000000..73a183b --- /dev/null +++ b/test/mocks/restartmanager_mock.cc @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide restartmanager mock + ******************************************************************************/ + +#include "restartmanager_mock.h" + +namespace { +MockRestartmanager *g_restartmanager_mock = NULL; +} + +void MockRestartmanager_SetMock(MockRestartmanager *mock) +{ + g_restartmanager_mock = mock; +} diff --git a/test/mocks/restartmanager_mock.h b/test/mocks/restartmanager_mock.h new file mode 100644 index 0000000..a1100e0 --- /dev/null +++ b/test/mocks/restartmanager_mock.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide restartmanager mock + ******************************************************************************/ + +#ifndef RESTARTMANAGER_MOCK_H_ +#define RESTARTMANAGER_MOCK_H_ + +#include +#include "restartmanager.h" + +class MockRestartmanager { +public: +}; + +void MockRestartmanager_SetMock(MockRestartmanager *mock); + +#endif diff --git a/test/mocks/runtime_mock.cc b/test/mocks/runtime_mock.cc new file mode 100644 index 0000000..2995a56 --- /dev/null +++ b/test/mocks/runtime_mock.cc @@ -0,0 +1,74 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide runtime mock + ******************************************************************************/ + +#include "runtime_mock.h" + +namespace { +MockRuntime *g_runtime_mock = NULL; +} + +void MockRuntime_SetMock(MockRuntime *mock) +{ + g_runtime_mock = mock; +} + +int runtime_pause(const char *name, const char *runtime, const rt_pause_params_t *params) +{ + if (g_runtime_mock != nullptr) { + return g_runtime_mock->RuntimePause(name, runtime, params); + } + return 0; +} + +int runtime_resources_stats(const char *name, const char *runtime, const rt_stats_params_t *params, + struct engine_container_resources_stats_info *rs_stats) +{ + if (g_runtime_mock != nullptr) { + return g_runtime_mock->RuntimeResourcesStats(name, runtime, params, rs_stats); + } + return 0; +} + +int runtime_resume(const char *name, const char *runtime, const rt_resume_params_t *params) +{ + if (g_runtime_mock != nullptr) { + return g_runtime_mock->RuntimeResume(name, runtime, params); + } + return 0; +} + +int runtime_update(const char *name, const char *runtime, const rt_update_params_t *params) +{ + if (g_runtime_mock != nullptr) { + return g_runtime_mock->RuntimeUpdate(name, runtime, params); + } + return 0; +} + +int runtime_resize(const char *name, const char *runtime, const rt_resize_params_t *params) +{ + if (g_runtime_mock != nullptr) { + return g_runtime_mock->RuntimeResize(name, runtime, params); + } + return 0; +} + +int runtime_exec_resize(const char *name, const char *runtime, const rt_exec_resize_params_t *params) +{ + if (g_runtime_mock != nullptr) { + return g_runtime_mock->RuntimeExecResize(name, runtime, params); + } + return 0; +} diff --git a/test/mocks/runtime_mock.h b/test/mocks/runtime_mock.h new file mode 100644 index 0000000..99f9b2d --- /dev/null +++ b/test/mocks/runtime_mock.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide runtime mock + ******************************************************************************/ + +#ifndef RUNTIME_MOCK_H_ +#define RUNTIME_MOCK_H_ + +#include +#include "runtime.h" + +class MockRuntime { +public: + MOCK_METHOD3(RuntimePause, int(const char *name, const char *runtime, const rt_pause_params_t *params)); + MOCK_METHOD3(RuntimeResume, int(const char *name, const char *runtime, const rt_resume_params_t *params)); + MOCK_METHOD3(RuntimeUpdate, int(const char *name, const char *runtime, const rt_update_params_t *params)); + MOCK_METHOD3(RuntimeResize, int(const char *name, const char *runtime, const rt_resize_params_t *params)); + MOCK_METHOD3(RuntimeExecResize, int(const char *name, const char *runtime, const rt_exec_resize_params_t *params)); + MOCK_METHOD4(RuntimeResourcesStats, int(const char *name, const char *runtime, const rt_stats_params_t *params, + struct engine_container_resources_stats_info *rs_stats)); +}; + +void MockRuntime_SetMock(MockRuntime* mock); + +#endif diff --git a/test/mocks/selinux_label_mock.cc b/test/mocks/selinux_label_mock.cc new file mode 100644 index 0000000..89e7768 --- /dev/null +++ b/test/mocks/selinux_label_mock.cc @@ -0,0 +1,81 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-11 + * Description: provide selinux label mock + ******************************************************************************/ + +#include "selinux_label_mock.h" + +namespace { +MockSelinuxLabel *g_selinux_label_mock = NULL; +} + +void SelinuxLabel_SetMock(MockSelinuxLabel* mock) +{ + g_selinux_label_mock = mock; +} + +int selinux_state_init(void) +{ + if (g_selinux_label_mock != nullptr) { + return g_selinux_label_mock->SelinuxStateInit(); + } + return 0; +} + +void selinux_set_disabled() +{ + if (g_selinux_label_mock != nullptr) { + g_selinux_label_mock->SelinuxSetDisabled(); + } +} + + +bool selinux_get_enable() +{ + if (g_selinux_label_mock != nullptr) { + return g_selinux_label_mock->SelinuxGetEnable(); + } + return false; +} + +int init_label(const char **label_opts, size_t label_opts_len, char **process_label, char **mount_label) +{ + if (g_selinux_label_mock != nullptr) { + return g_selinux_label_mock->InitLabel(label_opts, label_opts_len, process_label, mount_label); + } + return 0; +} + +int relabel(const char *path, const char *file_label, bool shared) +{ + if (g_selinux_label_mock != nullptr) { + return g_selinux_label_mock->Relabel(path, file_label, shared); + } + return 0; +} + +int get_disable_security_opt(char ***labels, size_t *labels_len) +{ + if (g_selinux_label_mock != nullptr) { + return g_selinux_label_mock->GetDisableSecurityOpt(labels, labels_len); + } + return 0; +} + +int dup_security_opt(const char *src, char ***dst, size_t *len) +{ + if (g_selinux_label_mock != nullptr) { + return g_selinux_label_mock->DupSecurityOpt(src, dst, len); + } + return 0; +} diff --git a/test/mocks/selinux_label_mock.h b/test/mocks/selinux_label_mock.h new file mode 100644 index 0000000..eaf2f69 --- /dev/null +++ b/test/mocks/selinux_label_mock.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-11 + * Description: provide selinux label mock + ******************************************************************************/ + + +#ifndef SELINUX_LABEL_MOCK_H_ +#define SELINUX_LABEL_MOCK_H_ + +#include +#include "selinux_label.h" + +class MockSelinuxLabel { +public: + virtual ~MockSelinuxLabel() = default; + MOCK_METHOD0(SelinuxStateInit, int(void)); + MOCK_METHOD0(SelinuxSetDisabled, void(void)); + MOCK_METHOD0(SelinuxGetEnable, bool(void)); + MOCK_METHOD4(InitLabel, + int(const char **label_opts, size_t label_opts_len, char **process_label, char **mount_label)); + MOCK_METHOD3(Relabel, int(const char *path, const char *file_label, bool shared)); + MOCK_METHOD2(GetDisableSecurityOpt, int(char ***labels, size_t *labels_len)); + MOCK_METHOD3(DupSecurityOpt, int(const char *src, char ***dst, size_t *len)); +}; + +void SelinuxLabel_SetMock(MockSelinuxLabel* mock); + +#endif // SELINUX_LABEL_MOCK_H_ diff --git a/test/mocks/selinux_mock.cc b/test/mocks/selinux_mock.cc new file mode 100644 index 0000000..e6ed358 --- /dev/null +++ b/test/mocks/selinux_mock.cc @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-11 + * Description: provide selinux mock + ******************************************************************************/ + +#include "selinux_mock.h" + +namespace { +MockSelinux *g_selinux_mock = NULL; +} + +void Selinux_SetMock(MockSelinux* mock) +{ + g_selinux_mock = mock; +} + +int selinuxfs_exists(void) +{ + if (g_selinux_mock != nullptr) { + return g_selinux_mock->SelinuxfsExists(); + } + return 0; +} \ No newline at end of file diff --git a/test/mocks/selinux_mock.h b/test/mocks/selinux_mock.h new file mode 100644 index 0000000..81466f9 --- /dev/null +++ b/test/mocks/selinux_mock.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-11 + * Description: provide selinux mock + ******************************************************************************/ + + +#ifndef SELINUX_MOCK_H_ +#define SELINUX_MOCK_H_ + +#include +#include + +class MockSelinux { +public: + virtual ~MockSelinux() = default; + MOCK_METHOD0(SelinuxfsExists, int(void)); +}; + +void Selinux_SetMock(MockSelinux* mock); + +#endif // SELINUX_LABEL_MOCK_H_ diff --git a/test/mocks/specs_mock.cc b/test/mocks/specs_mock.cc new file mode 100644 index 0000000..a426c67 --- /dev/null +++ b/test/mocks/specs_mock.cc @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide specs mock + ******************************************************************************/ + +#include "specs_mock.h" + +namespace { +MockSpecs *g_specs_mock = NULL; +} + +void MockSpecs_SetMock(MockSpecs *mock) +{ + g_specs_mock = mock; +} + +oci_runtime_spec *load_oci_config(const char *rootpath, const char *name) +{ + if (g_specs_mock != nullptr) { + return g_specs_mock->LoadOciConfig(rootpath, name); + } + return nullptr; +} + +int merge_conf_cgroup(oci_runtime_spec *oci_spec, const host_config *host_spec) +{ + if (g_specs_mock != nullptr) { + return g_specs_mock->MergeConfCgroup(oci_spec, host_spec); + } + return 0; +} + +int save_oci_config(const char *id, const char *rootpath, const oci_runtime_spec *oci_spec) +{ + if (g_specs_mock != nullptr) { + return g_specs_mock->SaveOciConfig(id, rootpath, oci_spec); + } + return 0; +} diff --git a/test/mocks/specs_mock.h b/test/mocks/specs_mock.h new file mode 100644 index 0000000..6b9849f --- /dev/null +++ b/test/mocks/specs_mock.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide specs mock + ******************************************************************************/ + +#ifndef SPECS_MOCK_H_ +#define SPECS_MOCK_H_ + +#include +#include "specs.h" + +class MockSpecs { +public: + MOCK_METHOD2(LoadOciConfig, oci_runtime_spec * (const char *rootpath, const char *name)); + MOCK_METHOD2(MergeConfCgroup, int(oci_runtime_spec *oci_spec, const host_config *host_spec)); + MOCK_METHOD3(SaveOciConfig, int(const char *id, const char *rootpath, const oci_runtime_spec *oci_spec)); +}; + +void MockSpecs_SetMock(MockSpecs* mock); + +#endif diff --git a/test/mocks/syscall_mock.cc b/test/mocks/syscall_mock.cc new file mode 100644 index 0000000..da6f57a --- /dev/null +++ b/test/mocks/syscall_mock.cc @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-11 + * Description: provide syscall mock + ******************************************************************************/ + +#include "syscall_mock.h" + +namespace { +MockSyscall *g_syscall_mock = NULL; +} + +void Syscall_SetMock(MockSyscall* mock) +{ + g_syscall_mock = mock; +} + +int statfs(const char *path, struct statfs *buf) +{ + if (g_syscall_mock != nullptr) { + return g_syscall_mock->Statfs(path, buf); + } + return 0; +} \ No newline at end of file diff --git a/test/mocks/syscall_mock.h b/test/mocks/syscall_mock.h new file mode 100644 index 0000000..5196506 --- /dev/null +++ b/test/mocks/syscall_mock.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-11 + * Description: syscall mock + ******************************************************************************/ + + +#ifndef SYSCALL_MOCK_H_ +#define SYSCALL_MOCK_H_ + +#include +#include + +class MockSyscall { +public: + virtual ~MockSyscall() = default; + MOCK_METHOD2(Statfs, int(const char *path, struct statfs *buf)); +}; + +void Syscall_SetMock(MockSyscall* mock); + +#endif // SYSCALL_MOCK_H_ diff --git a/test/mocks/sysinfo_mock.cc b/test/mocks/sysinfo_mock.cc new file mode 100644 index 0000000..cb1eff5 --- /dev/null +++ b/test/mocks/sysinfo_mock.cc @@ -0,0 +1,63 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide sysinfo mock + ******************************************************************************/ + +#include "sysinfo_mock.h" + +namespace { +MockSysinfo *g_sysinfo_mock = NULL; +} + +void MockSysinfo_SetMock(MockSysinfo *mock) +{ + g_sysinfo_mock = mock; +} + +uint64_t get_default_total_mem_size(void) +{ + if (g_sysinfo_mock != nullptr) { + return g_sysinfo_mock->GetDefaultTotalMemSize(); + } + return 0; +} + +mountinfo_t *find_mount_info(mountinfo_t **minfos, const char *dir) +{ + if (g_sysinfo_mock != nullptr) { + return g_sysinfo_mock->FindMountInfo(minfos, dir); + } + return nullptr; +} + +void free_mounts_info(mountinfo_t **minfos) +{ + if (g_sysinfo_mock != nullptr) { + return g_sysinfo_mock->FreeMountsInfo(minfos); + } +} + +char *validate_hugetlb(const char *pagesize, uint64_t limit) +{ + if (g_sysinfo_mock != nullptr) { + return g_sysinfo_mock->ValidateHugetlb(pagesize, limit); + } + return nullptr; +} + +void free_sysinfo(sysinfo_t *sysinfo) +{ + if (g_sysinfo_mock != nullptr) { + return g_sysinfo_mock->FreeSysinfo(sysinfo); + } +} diff --git a/test/mocks/sysinfo_mock.h b/test/mocks/sysinfo_mock.h new file mode 100644 index 0000000..1c3d9b4 --- /dev/null +++ b/test/mocks/sysinfo_mock.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide sysinfo mock + ******************************************************************************/ + +#ifndef SYSINFO_MOCK_H_ +#define SYSINFO_MOCK_H_ + +#include +#include "sysinfo.h" + +class MockSysinfo { +public: + MOCK_METHOD0(GetDefaultTotalMemSize, uint64_t(void)); + MOCK_METHOD2(FindMountInfo, mountinfo_t*(mountinfo_t **minfos, const char *dir)); + MOCK_METHOD1(FreeMountsInfo, void(mountinfo_t **minfos)); + MOCK_METHOD2(ValidateHugetlb, char*(const char *pagesize, uint64_t limit)); + MOCK_METHOD1(FreeSysinfo, void(sysinfo_t *sysinfo)); +}; + +void MockSysinfo_SetMock(MockSysinfo* mock); + +#endif diff --git a/test/mocks/verify_mock.cc b/test/mocks/verify_mock.cc new file mode 100644 index 0000000..6339687 --- /dev/null +++ b/test/mocks/verify_mock.cc @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide verify mock + ******************************************************************************/ + +#include "verify_mock.h" + +namespace { +MockVerify *g_verify_mock = NULL; +} + +void MockVerify_SetMock(MockVerify *mock) +{ + g_verify_mock = mock; +} + +int verify_host_config_settings(host_config *hostconfig, bool update) +{ + if (g_verify_mock != nullptr) { + return g_verify_mock->VerifyHostConfigSettings(hostconfig, update); + } + return 0; +} diff --git a/test/mocks/verify_mock.h b/test/mocks/verify_mock.h new file mode 100644 index 0000000..97a4ada --- /dev/null +++ b/test/mocks/verify_mock.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide verify mock + ******************************************************************************/ + +#ifndef VERIFY_MOCK_H_ +#define VERIFY_MOCK_H_ + +#include +#include "verify.h" + +class MockVerify { +public: + MOCK_METHOD2(VerifyHostConfigSettings, int(host_config *hostconfig, bool update)); +}; + +void MockVerify_SetMock(MockVerify* mock); + +#endif diff --git a/test/runtime/CMakeLists.txt b/test/runtime/CMakeLists.txt new file mode 100644 index 0000000..3d6b5df --- /dev/null +++ b/test/runtime/CMakeLists.txt @@ -0,0 +1,4 @@ +project(iSulad_LLT) + +add_subdirectory(lcr) +add_subdirectory(isula) diff --git a/test/runtime/isula/CMakeLists.txt b/test/runtime/isula/CMakeLists.txt new file mode 100644 index 0000000..b9e44e7 --- /dev/null +++ b/test/runtime/isula/CMakeLists.txt @@ -0,0 +1,67 @@ +project(iSulad_LLT) + +SET(EXE isula_rt_ops_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/sha256/sha256.c + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/path.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/libisulad.c + ${CMAKE_BINARY_DIR}/json/defs.c + ${CMAKE_BINARY_DIR}/json/container_config_v2.c + ${CMAKE_BINARY_DIR}/json/container_config.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_spec.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/sysinfo.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_config_linux.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/commander.c + ${CMAKE_BINARY_DIR}/json/isulad_daemon_configs.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad/arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/image/oci/oci_llt_common.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/containers_store_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/namespace_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/container_unix_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/engine_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/isulad_config_mock.cc + ${CMAKE_BINARY_DIR}/json/imagetool_image.c + ${CMAKE_BINARY_DIR}/json/oci_image_spec.c + ${CMAKE_BINARY_DIR}/json/shim_client_process_state.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_state.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/runtime/isula/isula_rt_ops.c + isula_rt_ops_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/events + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/runtime + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/runtime/isula + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/engines + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/graphdriver + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks + ) + +#set_target_properties(${EXE} PROPERTIES LINK_FLAGS) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/runtime/isula/isula_rt_ops_llt.cc b/test/runtime/isula/isula_rt_ops_llt.cc new file mode 100644 index 0000000..ac42b45 --- /dev/null +++ b/test/runtime/isula/isula_rt_ops_llt.cc @@ -0,0 +1,132 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Description: isula runtime ops llt + * Author: jingrui + * Create: 2020-02-15 + */ + +#include +#include +#include +#include "mock.h" +#include "isula_rt_ops.h" +#include +#include +#include "engine_mock.h" +#include "isulad_config_mock.h" +#include "utils.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class IsulaRtOpsUnitTest : public testing::Test { +public: + void SetUp() override + { + MockEngine_SetMock(&m_engine); + ::testing::Mock::AllowLeak(&m_engine); + + MockIsuladConf_SetMock(&m_isulad_conf); + ::testing::Mock::AllowLeak(&m_isulad_conf); + } + void TearDown() override + { + MockEngine_SetMock(nullptr); + MockIsuladConf_SetMock(nullptr); + } + + NiceMock m_engine; + NiceMock m_isulad_conf; +}; + +TEST(isula_rt_ops_llt, test_rt_isula_detect) +{ + // All parameter NULL + ASSERT_FALSE(rt_isula_detect(NULL)); + + ASSERT_TRUE(rt_isula_detect("kata-runtime")); + + ASSERT_TRUE(rt_isula_detect("kata-me")); + ASSERT_TRUE(rt_isula_detect("runc")); + + ASSERT_FALSE(rt_isula_detect("lcr")); +} + + +TEST_F(IsulaRtOpsUnitTest, test_rt_isula_create) +{ + ASSERT_EQ(rt_isula_create(nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_create("123", nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_create("123", "kata-runtime", nullptr), -1); +} + +TEST_F(IsulaRtOpsUnitTest, test_rt_isula_start) +{ + rt_start_params_t params = {}; + ASSERT_EQ(rt_isula_start(nullptr, nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_start("123", nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_start("123", "kata-runtime", nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_start("123", "kata-runtime", ¶ms, nullptr), -1); +} + +TEST_F(IsulaRtOpsUnitTest, test_rt_isula_clean_resource) +{ + rt_clean_params_t params = {}; + + ASSERT_EQ(rt_isula_clean_resource(nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_clean_resource("123", nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_clean_resource("123", "kata-runtime", nullptr), -1); + ASSERT_EQ(rt_isula_clean_resource("123", "kata-runtime", ¶ms), -1); + params.statepath = "/var/run/isulad/kata-runtime/123"; + ASSERT_EQ(rt_isula_clean_resource("123", "kata-runtime", ¶ms), 0); +} + +TEST_F(IsulaRtOpsUnitTest, test_rt_isula_rm) +{ + rt_rm_params_t params = {}; + ASSERT_EQ(rt_isula_rm(nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_rm("123", nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_rm("123", "kata-runtime", nullptr), -1); + ASSERT_EQ(rt_isula_rm("123", "kata-runtime", ¶ms), -1); + params.rootpath = "/var/lib/isulad/kata-runtime/123"; + ASSERT_EQ(rt_isula_rm("123", "kata-runtime", ¶ms), 0); +} + +TEST_F(IsulaRtOpsUnitTest, test_rt_isula_exec) +{ + rt_exec_params_t params = {}; + ASSERT_EQ(rt_isula_exec(nullptr, nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_exec("123", nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_exec("123", "kata-runtime", nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_exec("123", "kata-runtime", ¶ms, nullptr), -1); +} + +TEST_F(IsulaRtOpsUnitTest, test_rt_isula_status) +{ + rt_status_params_t params = {}; + struct engine_container_status_info status = {}; + ASSERT_EQ(rt_isula_status(nullptr, nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_status("123", nullptr, nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_status("123", "kata-runtime", nullptr, nullptr), -1); + ASSERT_EQ(rt_isula_status("123", "kata-runtime", ¶ms, nullptr), -1); + params.state = "/var/run/isulad/kata-runtime"; + ASSERT_EQ(rt_isula_status("123", "kata-runtime", ¶ms, &status), -1); +} diff --git a/test/runtime/lcr/CMakeLists.txt b/test/runtime/lcr/CMakeLists.txt new file mode 100644 index 0000000..32ad5ff --- /dev/null +++ b/test/runtime/lcr/CMakeLists.txt @@ -0,0 +1,66 @@ +project(iSulad_LLT) + +SET(EXE lcr_rt_ops_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/sha256/sha256.c + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/path.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/libisulad.c + ${CMAKE_BINARY_DIR}/json/defs.c + ${CMAKE_BINARY_DIR}/json/container_config_v2.c + ${CMAKE_BINARY_DIR}/json/container_config.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_spec.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/sysinfo.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_config_linux.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/commander.c + ${CMAKE_BINARY_DIR}/json/isulad_daemon_configs.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad/arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/image/oci/oci_llt_common.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/containers_store_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/namespace_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/container_unix_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/engine_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/isulad_config_mock.cc + ${CMAKE_BINARY_DIR}/json/imagetool_image.c + ${CMAKE_BINARY_DIR}/json/oci_image_spec.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/runtime/lcr/lcr_rt_ops.c + lcr_rt_ops_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/events + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/runtime + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/runtime/lcr + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/engines + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/graphdriver + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks + ) + +#set_target_properties(${EXE} PROPERTIES LINK_FLAGS) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/runtime/lcr/lcr_rt_ops_llt.cc b/test/runtime/lcr/lcr_rt_ops_llt.cc new file mode 100644 index 0000000..7afce71 --- /dev/null +++ b/test/runtime/lcr/lcr_rt_ops_llt.cc @@ -0,0 +1,595 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Description: lcr runtime ops llt + * Author: lifeng + * Create: 2020-02-15 + */ + +#include +#include +#include +#include "mock.h" +#include "lcr_rt_ops.h" +#include +#include +#include "engine_mock.h" +#include "isulad_config_mock.h" +#include "utils.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class LcrRtOpsUnitTest : public testing::Test { +public: + void SetUp() override + { + MockEngine_SetMock(&m_engine); + ::testing::Mock::AllowLeak(&m_engine); + + MockIsuladConf_SetMock(&m_isulad_conf); + ::testing::Mock::AllowLeak(&m_isulad_conf); + } + void TearDown() override + { + MockEngine_SetMock(nullptr); + MockIsuladConf_SetMock(nullptr); + } + + NiceMock m_engine; + NiceMock m_isulad_conf; +}; + +TEST(lcr_rt_ops_llt, test_rt_lcr_detect) +{ + // All parameter NULL + ASSERT_FALSE(rt_lcr_detect(NULL)); + + ASSERT_TRUE(rt_lcr_detect("lcr")); + + ASSERT_TRUE(rt_lcr_detect("LCR")); + + ASSERT_FALSE(rt_lcr_detect("test")); +} + +bool RuntimeCreateContainer(const char *id, const char *root, void *config) +{ + + if (id == nullptr || root == nullptr) { + return false; + } + + return true; +} + +bool RuntimeStartContainer(const engine_start_request_t *request) +{ + + if (request == nullptr) { + return false; + } + + if (request->name == nullptr) { + return false; + } + + return true; +} + +bool RuntimeCleanContainer(const char *name, const char *lcrpath, const char *logpath, const char *loglevel, + pid_t pid) +{ + + if (name == nullptr) { + return false; + } + + return true; +} + +bool RuntimeRmContainer(const char *name, const char *enginepath) +{ + + if (name == nullptr || enginepath == nullptr) { + return false; + } + + return true; +} + +int RuntimeStatusContainer(const char *name, const char *enginepath, struct engine_container_status_info *status) +{ + + if (name == nullptr || enginepath == nullptr || status == nullptr) { + return -1; + } + + return 0; +} + +int RuntimeStatsContainer(const char *name, const char *enginepath, + struct engine_container_resources_stats_info *rs_stats) +{ + + if (name == nullptr || enginepath == nullptr || rs_stats == nullptr) { + return -1; + } + + return 0; +} + +bool RuntimeExecContainer(const engine_exec_request_t *request, int *exit_code) +{ + + if (request == nullptr || exit_code == nullptr || request->lcrpath == nullptr) { + return false; + } + + return true; +} + +bool RuntimePauseContainer(const char *name, const char *enginepath) +{ + + if (name == nullptr || enginepath == nullptr) { + return false; + } + + return true; +} + +bool RuntimeResumeContainer(const char *name, const char *enginepath) +{ + + if (name == nullptr || enginepath == nullptr) { + return false; + } + + return true; +} + +bool RuntimeAttachContainer(const char *name, const char *enginepath, char *in_fifo, char *out_fifo, + char *err_fifo) +{ + + if (name == nullptr || enginepath == nullptr) { + return false; + } + + return true; +} + +bool RuntimeUpdateContainer(const char *name, const char *enginepath, const struct engine_cgroup_resources *cr) +{ + + if (name == nullptr || enginepath == nullptr) { + return false; + } + + return true; +} + +bool RuntimeResizeContainer(const char *name, const char *lcrpath, unsigned int height, unsigned int width) +{ + + if (name == nullptr || lcrpath == nullptr) { + return false; + } + + return true; +} + +bool RuntimeExecResizeContainer(const char *name, const char *lcrpath, const char *suffix, unsigned int height, + unsigned int width) +{ + + if (name == nullptr || lcrpath == nullptr) { + return false; + } + + return true; +} + +bool RuntimeListPidsContainer(const char *name, const char *rootpath, pid_t **pids, size_t *pids_len) +{ + + if (name == nullptr || rootpath == nullptr) { + return false; + } + + return true; +} + +struct engine_operation g_engine_ops; + +struct engine_operation *invoke_engines_get_handler(const char *runtime) +{ + if (runtime == nullptr) { + return nullptr; + } + g_engine_ops.engine_create_op = &RuntimeCreateContainer; + g_engine_ops.engine_start_op = &RuntimeStartContainer; + g_engine_ops.engine_clean_op = &RuntimeCleanContainer; + g_engine_ops.engine_delete_op = &RuntimeRmContainer; + g_engine_ops.engine_get_container_status_op = &RuntimeStatusContainer; + g_engine_ops.engine_get_container_resources_stats_op = &RuntimeStatsContainer; + g_engine_ops.engine_exec_op = &RuntimeExecContainer; + g_engine_ops.engine_pause_op = &RuntimePauseContainer; + g_engine_ops.engine_resume_op = &RuntimeResumeContainer; + g_engine_ops.engine_console_op = &RuntimeAttachContainer; + g_engine_ops.engine_update_op = &RuntimeUpdateContainer; + g_engine_ops.engine_resize_op = &RuntimeResizeContainer; + g_engine_ops.engine_exec_resize_op = &RuntimeExecResizeContainer; + g_engine_ops.engine_get_container_pids_op = &RuntimeListPidsContainer; + + return &g_engine_ops; +} + +/* conf get routine rootdir */ +char *invoke_conf_get_routine_rootdir(const char *runtime) +{ + if (runtime == nullptr) { + return nullptr; + } + + return util_strdup_s("/var/lib/isulad/engines/lcr"); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_create) +{ + rt_create_params_t params = {}; + + ASSERT_EQ(rt_lcr_create(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_create("123", "lcr", ¶ms), 0); + + ASSERT_EQ(rt_lcr_create(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_create("123", nullptr, ¶ms), -1); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +static char *get_absolute_path(const char *file) +{ + char base_path[PATH_MAX] = {0}; + char *json_file = NULL; + + if (getcwd(base_path, PATH_MAX) == NULL) { + return NULL; + } + + json_file = util_path_join(base_path, file); + if (json_file == NULL) { + return NULL; + } + + return json_file; +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_start) +{ + rt_start_params_t params = {}; + container_pid_t pid_info = {}; + char *pid_path = get_absolute_path("runtime/lcr/pid.file"); + + ASSERT_EQ(rt_lcr_start(nullptr, nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + params.container_pidfile = pid_path; + + ASSERT_EQ(rt_lcr_start("123", "lcr", ¶ms, &pid_info), 0); + ASSERT_EQ(pid_info.pid, 18715); + ASSERT_EQ(pid_info.ppid, 18712); + ASSERT_EQ(pid_info.start_time, 98072004); + ASSERT_EQ(pid_info.pstart_time, 98072003); + + ASSERT_EQ(rt_lcr_start(nullptr, "lcr", ¶ms, &pid_info), -1); + + ASSERT_EQ(rt_lcr_start("123", nullptr, ¶ms, nullptr), -1); + + free(pid_path); + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_restart) +{ + ASSERT_EQ(rt_lcr_restart(nullptr, nullptr, nullptr), RUNTIME_NOT_IMPLEMENT_RESET); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_clean_resource) +{ + rt_clean_params_t params = {}; + + ASSERT_EQ(rt_lcr_clean_resource(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_clean_resource("123", "lcr", ¶ms), 0); + + ASSERT_EQ(rt_lcr_clean_resource(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_clean_resource("123", nullptr, ¶ms), -1); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_rm) +{ + rt_rm_params_t params = {}; + + ASSERT_EQ(rt_lcr_rm(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_rm("123", "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_rm(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_rm("123", nullptr, ¶ms), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_rm("123", "lcr", ¶ms), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_status) +{ + rt_status_params_t params = {}; + struct engine_container_status_info status = {}; + + ASSERT_EQ(rt_lcr_status(nullptr, nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_status("123", "lcr", ¶ms, nullptr), -1); + + ASSERT_EQ(rt_lcr_status(nullptr, "lcr", ¶ms, &status), -1); + + ASSERT_EQ(rt_lcr_status("123", nullptr, ¶ms, &status), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_status("123", "lcr", ¶ms, nullptr), -1); + + ASSERT_EQ(rt_lcr_status("123", "lcr", ¶ms, &status), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_resources_stats) +{ + rt_stats_params_t params = {}; + struct engine_container_resources_stats_info status = {}; + + ASSERT_EQ(rt_lcr_resources_stats(nullptr, nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_resources_stats("123", "lcr", ¶ms, nullptr), -1); + + ASSERT_EQ(rt_lcr_resources_stats(nullptr, "lcr", ¶ms, &status), -1); + + ASSERT_EQ(rt_lcr_resources_stats("123", nullptr, ¶ms, &status), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_resources_stats("123", "lcr", ¶ms, nullptr), -1); + + ASSERT_EQ(rt_lcr_resources_stats("123", "lcr", ¶ms, &status), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_exec) +{ + rt_exec_params_t params = {}; + int pid = 0; + + ASSERT_EQ(rt_lcr_exec(nullptr, nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_exec("123", "lcr", ¶ms, nullptr), -1); + + ASSERT_EQ(rt_lcr_exec(nullptr, "lcr", ¶ms, &pid), -1); + + ASSERT_EQ(rt_lcr_exec("123", nullptr, ¶ms, &pid), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_exec("123", "lcr", ¶ms, nullptr), -1); + + ASSERT_EQ(rt_lcr_exec("123", "lcr", ¶ms, &pid), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_pause) +{ + rt_pause_params_t params = {}; + + ASSERT_EQ(rt_lcr_pause(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_pause("123", "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_pause(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_pause("123", nullptr, ¶ms), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_pause("123", "lcr", ¶ms), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_resume) +{ + rt_resume_params_t params = {}; + + ASSERT_EQ(rt_lcr_resume(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_resume("123", "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_resume(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_resume("123", nullptr, ¶ms), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_resume("123", "lcr", ¶ms), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_attach) +{ + rt_attach_params_t params = {}; + + ASSERT_EQ(rt_lcr_attach(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_attach("123", "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_attach(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_attach("123", nullptr, ¶ms), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_attach("123", "lcr", ¶ms), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_update) +{ + rt_update_params_t params = {}; + + ASSERT_EQ(rt_lcr_update(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_update("123", "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_update(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_update("123", nullptr, ¶ms), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_update("123", "lcr", ¶ms), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_resize) +{ + rt_resize_params_t params = {}; + + ASSERT_EQ(rt_lcr_resize(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_resize("123", "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_resize(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_resize("123", nullptr, ¶ms), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_resize("123", "lcr", ¶ms), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_exec_resize) +{ + rt_exec_resize_params_t params = {}; + + ASSERT_EQ(rt_lcr_exec_resize(nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_exec_resize("123", "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_exec_resize(nullptr, "lcr", ¶ms), -1); + + ASSERT_EQ(rt_lcr_exec_resize("123", nullptr, ¶ms), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_exec_resize("123", "lcr", ¶ms), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(LcrRtOpsUnitTest, test_rt_lcr_listpids) +{ + rt_listpids_params_t params = {}; + rt_listpids_out_t out = {}; + + ASSERT_EQ(rt_lcr_listpids(nullptr, nullptr, nullptr, nullptr), -1); + + EXPECT_CALL(m_isulad_conf, GetRuntimeDir(_)).WillRepeatedly(Invoke(invoke_conf_get_routine_rootdir)); + EXPECT_CALL(m_engine, EngineGetHandler(_)).WillRepeatedly(Invoke(invoke_engines_get_handler)); + + ASSERT_EQ(rt_lcr_listpids("123", "lcr", ¶ms, nullptr), -1); + + ASSERT_EQ(rt_lcr_listpids(nullptr, "lcr", ¶ms, &out), -1); + + ASSERT_EQ(rt_lcr_listpids("123", nullptr, ¶ms, &out), -1); + + params.rootpath = "/var/lib/isulad"; + ASSERT_EQ(rt_lcr_listpids("123", "lcr", ¶ms, nullptr), -1); + + ASSERT_EQ(rt_lcr_listpids("123", "lcr", ¶ms, &out), 0); + + testing::Mock::VerifyAndClearExpectations(&m_engine); + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} diff --git a/test/runtime/lcr/pid.file b/test/runtime/lcr/pid.file new file mode 100644 index 0000000..433b0e8 --- /dev/null +++ b/test/runtime/lcr/pid.file @@ -0,0 +1 @@ +18715 98072004 18712 98072003 diff --git a/test/services/CMakeLists.txt b/test/services/CMakeLists.txt new file mode 100644 index 0000000..08e0735 --- /dev/null +++ b/test/services/CMakeLists.txt @@ -0,0 +1,4 @@ +project(iSulad_LLT) + +add_subdirectory(graphdriver) +add_subdirectory(execution) diff --git a/test/services/execution/CMakeLists.txt b/test/services/execution/CMakeLists.txt new file mode 100644 index 0000000..724c02e --- /dev/null +++ b/test/services/execution/CMakeLists.txt @@ -0,0 +1,4 @@ +project(iSulad_LLT) + +add_subdirectory(spec) +add_subdirectory(execute) diff --git a/test/services/execution/execute/CMakeLists.txt b/test/services/execution/execute/CMakeLists.txt new file mode 100644 index 0000000..a03abaf --- /dev/null +++ b/test/services/execution/execute/CMakeLists.txt @@ -0,0 +1,3 @@ +project(iSulad_LLT) + +add_subdirectory(execution_extend) diff --git a/test/services/execution/execute/execution_extend/CMakeLists.txt b/test/services/execution/execute/execution_extend/CMakeLists.txt new file mode 100644 index 0000000..fa44f4c --- /dev/null +++ b/test/services/execution/execute/execution_extend/CMakeLists.txt @@ -0,0 +1,82 @@ +project(iSulad_LLT) + +SET(EXE execution_extend_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/log.c + + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/error.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/filters.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/map/map.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/map/rb_tree.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/services/execution/execute/execution_extend.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/oci_runtime_hooks.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/runtime_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/containers_store_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/collector_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/containers_gc_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/container_unix_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/health_check_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/image_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/isulad_config_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/sysinfo_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/container_state_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/verify_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/engine_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/driver_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/restartmanager_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/specs_mock.cc + ${CMAKE_BINARY_DIR}/json/container_inspect.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_spec.c + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_BINARY_DIR}/json/container_stats_request.c + ${CMAKE_BINARY_DIR}/json/container_info.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_config_linux.c + ${CMAKE_BINARY_DIR}/json/defs.c + ${CMAKE_BINARY_DIR}/json/docker_types_mount_point.c + execution_extend_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/runtime + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/engines + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/image + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/services + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/services/execution/manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/services/execution/spec + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/services/execution/events + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/services/execution/execute + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/services/graphdriver + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../conf + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks + ${CMAKE_BINARY_DIR}/json + ) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/services/execution/execute/execution_extend/execution_extend_llt.cc b/test/services/execution/execute/execution_extend/execution_extend_llt.cc new file mode 100644 index 0000000..fe8ed96 --- /dev/null +++ b/test/services/execution/execute/execution_extend/execution_extend_llt.cc @@ -0,0 +1,246 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: jikui + * Create: 2020-02-25 + * Description: provide execution_extend llt test + ******************************************************************************/ + +#include "execution_extend.h" +#include +#include +#include "runtime_mock.h" +#include "containers_store_mock.h" +#include "container_state_mock.h" +#include "sysinfo_mock.h" +#include "health_check_mock.h" +#include "collector_mock.h" +#include "container_unix_mock.h" +#include "image_mock.h" +#include "isulad_config_mock.h" +#include "containers_gc_mock.h" +#include "engine_mock.h" +#include "driver_mock.h" +#include "restartmanager_mock.h" +#include "verify_mock.h" +#include "specs_mock.h" +#include "callback.h" +#include "utils.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class ExecutionExtendUnitTest : public testing::Test { +public: + void SetUp() override + { + MockRuntime_SetMock(&m_runtime); + MockContainersStore_SetMock(&m_containersStore); + MockCollector_SetMock(&m_collector); + MockContainersGc_SetMock(&m_containersGc); + MockContainerUnix_SetMock(&m_containerUnix); + MockHealthCheck_SetMock(&m_healthCheck); + MockIsuladConf_SetMock(&m_isuladConf); + MockImage_SetMock(&m_image); + MockSysinfo_SetMock(&m_sysinfo); + MockEngine_SetMock(&m_engine); + MockDriver_SetMock(&m_driver); + MockVerify_SetMock(&m_verify); + MockRestartmanager_SetMock(&m_restartmanager); + MockContainerState_SetMock(&m_containerState); + MockSpecs_SetMock(&m_specs); + ::testing::Mock::AllowLeak(&m_runtime); + ::testing::Mock::AllowLeak(&m_containersStore); + ::testing::Mock::AllowLeak(&m_collector); + ::testing::Mock::AllowLeak(&m_containersGc); + ::testing::Mock::AllowLeak(&m_containerUnix); + ::testing::Mock::AllowLeak(&m_healthCheck); + ::testing::Mock::AllowLeak(&m_image); + ::testing::Mock::AllowLeak(&m_isuladConf); + ::testing::Mock::AllowLeak(&m_sysinfo); + ::testing::Mock::AllowLeak(&m_engine); + ::testing::Mock::AllowLeak(&m_driver); + ::testing::Mock::AllowLeak(&m_restartmanager); + ::testing::Mock::AllowLeak(&m_containerState); + ::testing::Mock::AllowLeak(&m_verify); + ::testing::Mock::AllowLeak(&m_specs); + } + void TearDown() override + { + MockRuntime_SetMock(nullptr); + MockContainersStore_SetMock(nullptr); + MockCollector_SetMock(nullptr); + MockContainersGc_SetMock(nullptr); + MockContainerUnix_SetMock(nullptr); + MockHealthCheck_SetMock(nullptr); + MockImage_SetMock(nullptr); + MockIsuladConf_SetMock(nullptr); + MockSysinfo_SetMock(nullptr); + MockEngine_SetMock(nullptr); + MockDriver_SetMock(nullptr); + MockRestartmanager_SetMock(nullptr); + MockContainerState_SetMock(nullptr); + MockVerify_SetMock(nullptr); + MockSpecs_SetMock(nullptr); + } + + NiceMock m_runtime; + NiceMock m_containersStore; + NiceMock m_collector; + NiceMock m_containersGc; + NiceMock m_containerUnix; + NiceMock m_healthCheck; + NiceMock m_image; + NiceMock m_isuladConf; + NiceMock m_sysinfo; + NiceMock m_engine; + NiceMock m_driver; + NiceMock m_restartmanager; + NiceMock m_containerState; + NiceMock m_verify; + NiceMock m_specs; +}; + +int invokeRuntimePause(const char *name, const char *runtime, const rt_pause_params_t *params) +{ + return 0; +} + +int invokeRuntimeResume(const char *name, const char *runtime, const rt_resume_params_t *params) +{ + return 0; +} + +container_t *invokeContainersStoreGet(const char *id_or_name) +{ + if (id_or_name == nullptr) { + return nullptr; + } + container_t *cont = (container_t *)util_common_calloc_s(sizeof(container_t)); + cont->common_config = (container_config_v2_common_config *)util_common_calloc_s(sizeof( + container_config_v2_common_config)); + return cont; +} + +bool invokeGcIsGcProgress(const char *id) +{ + return false; +} + +int invokeContainerToDisk(const container_t *cont) +{ + return 0; +} + +void invokeContainerUnlock(container_t *cont) +{ + return; +} + +void invokeContainerLock(container_t *cont) +{ + return; +} + +void invokeContainerUnref(container_t *cont) +{ + return; +} + +void invokeUpdateHealthMonitor(const char *container_id) +{ + return; +} + +bool invokeIsRunning(container_state_t *s) +{ + return true; +} + +bool invokeIsPaused(container_state_t *s) +{ + return false; +} + +void invokeStateResetPaused(container_state_t *s) +{ + return; +} + +bool invokeIsRestarting(container_state_t *s) +{ + return false; +} + +void invokeContainerStateSetError(container_state_t *s, const char *err) +{ + return; +} + +void invokeStateSetPaused(container_state_t *s) +{ + return; +} + +TEST_F(ExecutionExtendUnitTest, test_container_extend_callback_init_pause) +{ + service_container_callback_t cb; + container_pause_request *request = (container_pause_request*)util_common_calloc_s(sizeof(container_pause_request)); + container_pause_response *response = (container_pause_response*)util_common_calloc_s(sizeof(container_pause_response)); + request->id = util_strdup_s("64ff21ebf4e4"); + + EXPECT_CALL(m_runtime, RuntimePause(_, _, _)).WillRepeatedly(Invoke(invokeRuntimePause)); + EXPECT_CALL(m_containersStore, ContainersStoreGet(_)).WillRepeatedly(Invoke(invokeContainersStoreGet)); + EXPECT_CALL(m_containerState, IsRunning(_)).WillRepeatedly(Invoke(invokeIsRunning)); + EXPECT_CALL(m_containersGc, GcIsGcProgress(_)).WillRepeatedly(Invoke(invokeGcIsGcProgress)); + EXPECT_CALL(m_containerState, IsPaused(_)).WillRepeatedly(Invoke(invokeIsPaused)); + EXPECT_CALL(m_containerState, IsRestarting(_)).WillRepeatedly(Invoke(invokeIsRestarting)); + EXPECT_CALL(m_containerUnix, ContainerToDisk(_)).WillRepeatedly(Invoke(invokeContainerToDisk)); + container_extend_callback_init(&cb); + ASSERT_EQ(cb.pause(request, &response), 0); + testing::Mock::VerifyAndClearExpectations(&m_runtime); + testing::Mock::VerifyAndClearExpectations(&m_containersStore); + testing::Mock::VerifyAndClearExpectations(&m_containerState); + testing::Mock::VerifyAndClearExpectations(&m_containersGc); + testing::Mock::VerifyAndClearExpectations(&m_containerUnix); +} + +TEST_F(ExecutionExtendUnitTest, test_container_extend_callback_init_resume) +{ + service_container_callback_t cb; + container_resume_request *request = (container_resume_request*)util_common_calloc_s(sizeof(container_resume_request)); + container_resume_response *response = (container_resume_response*)util_common_calloc_s(sizeof( + container_resume_response)); + request->id = util_strdup_s("64ff21ebf4e4"); + + EXPECT_CALL(m_runtime, RuntimeResume(_, _, _)).WillRepeatedly(Invoke(invokeRuntimeResume)); + EXPECT_CALL(m_containersStore, ContainersStoreGet(_)).WillRepeatedly(Invoke(invokeContainersStoreGet)); + EXPECT_CALL(m_containerState, IsRunning(_)).WillRepeatedly(Invoke(invokeIsRunning)); + EXPECT_CALL(m_containersGc, GcIsGcProgress(_)).WillRepeatedly(Invoke(invokeGcIsGcProgress)); + EXPECT_CALL(m_containerState, IsPaused(_)).WillOnce(Return(true)); + EXPECT_CALL(m_containerUnix, ContainerToDisk(_)).WillRepeatedly(Invoke(invokeContainerToDisk)); + container_extend_callback_init(&cb); + ASSERT_EQ(cb.resume(request, &response), 0); + testing::Mock::VerifyAndClearExpectations(&m_runtime); + testing::Mock::VerifyAndClearExpectations(&m_containersStore); + testing::Mock::VerifyAndClearExpectations(&m_containerState); + testing::Mock::VerifyAndClearExpectations(&m_containersGc); + testing::Mock::VerifyAndClearExpectations(&m_containerUnix); +} diff --git a/test/services/execution/spec/CMakeLists.txt b/test/services/execution/spec/CMakeLists.txt new file mode 100644 index 0000000..c8d06c8 --- /dev/null +++ b/test/services/execution/spec/CMakeLists.txt @@ -0,0 +1,79 @@ +project(iSulad_LLT) + +SET(EXE selinux_label_llt) +SET(MOCK_EXE selinux_label_mock_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/map/map.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/map/rb_tree.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/namespace_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/spec/selinux_label.c + ${CMAKE_BINARY_DIR}/json/json_common.c + selinux_label_llt.cc) + +add_executable(${MOCK_EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/map/map.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/map/rb_tree.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/namespace_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/syscall_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/selinux_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/spec/selinux_label.c + ${CMAKE_BINARY_DIR}/json/json_common.c + selinux_label_mock_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/spec + ${CMAKE_BINARY_DIR}/conf + ${CMAKE_BINARY_DIR}/json + ) + +target_include_directories(${MOCK_EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/execution/spec + ${CMAKE_BINARY_DIR}/conf + ${CMAKE_BINARY_DIR}/json + ) + +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${SELINUX_LIBRARY} -lyajl -lz) +target_link_libraries(${MOCK_EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${SELINUX_LIBRARY} -lyajl -lz) diff --git a/test/services/execution/spec/selinux_label_llt.cc b/test/services/execution/spec/selinux_label_llt.cc new file mode 100644 index 0000000..b5f612b --- /dev/null +++ b/test/services/execution/spec/selinux_label_llt.cc @@ -0,0 +1,237 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide selinux label unit test + ******************************************************************************/ + +#include "selinux_label.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "namespace_mock.h" +#include "utils.h" + +using namespace std; + +class SELinuxLabelUnitTest : public testing::Test { +protected: + void SetUp() override + { + selinux_state_init(); + } + void TearDown() override + { + std::cout << "selinux_state is the resident memory of the daemon." << + " The process exits and the memory is automatically released." << std::endl; + } +}; + +TEST_F(SELinuxLabelUnitTest, test_init_label_normal) +{ + const char *disable_label[] = { "disable" }; + const char *user_label[] = { "user:fakeuser" }; + const char *role_label[] = { "role:fakerole" }; + const char *type_label[] = { "type:faketype" }; + const char *level_label[] = { "level:s0:c1,c2" }; + const char *full_label[] = { "user:fakeuser", "level:s0:c1,c2", "type:faketype", "role:fakerole" }; + + std::vector> normal { + std::make_tuple(disable_label, 1, 0, "", ""), + std::make_tuple(user_label, 1, 0, "fakeuser:system_r:container_t:s0", "fakeuser:object_r:container_file_t:s0"), + std::make_tuple(role_label, 1, 0, "system_u:fakerole:container_t:s0", "system_u:object_r:container_file_t:s0"), + std::make_tuple(type_label, 1, 0, "system_u:system_r:faketype:s0", "system_u:object_r:container_file_t:s0"), + std::make_tuple(level_label, 1, 0, "system_u:system_r:container_t:s0:c1,c2", "system_u:object_r:container_file_t:s0:c1,c2"), + std::make_tuple(full_label, 4, 0, "fakeuser:fakerole:faketype:s0:c1,c2", "fakeuser:object_r:container_file_t:s0:c1,c2"), + std::make_tuple(nullptr, 0, 0, "system_u:system_r:container_t:s0", "system_u:object_r:container_file_t:s0"), + }; + + if (!is_selinux_enabled()) { + SUCCEED() << "WARNING: The current machine does not support SELinux"; + return; + } + + for (const auto &elem : normal) { + char *process_label = nullptr; + char *mount_label = nullptr; + + ASSERT_EQ(init_label(std::get<0>(elem), std::get<1>(elem), &process_label, &mount_label), std::get<2>(elem)); + if (!std::get<3>(elem).empty()) { + std::string processLabel { process_label }; + processLabel.resize(std::get<3>(elem).size()); + ASSERT_STREQ(processLabel.c_str(), std::get<3>(elem).c_str()); + free(process_label); + } else { + ASSERT_STREQ(process_label, nullptr); + } + + if (!std::get<4>(elem).empty()) { + std::string mountLabel { mount_label }; + mountLabel.resize(std::get<4>(elem).size()); + ASSERT_STREQ(mountLabel.c_str(), std::get<4>(elem).c_str()); + free(mount_label); + } else { + ASSERT_STREQ(mount_label, nullptr); + } + } +} + +TEST_F(SELinuxLabelUnitTest, test_init_label_abnormal) +{ + const char *invalid_key_label[] = { "xxx" }; + const char *invalid_value_label[] = { "user:" }; + + std::vector> normal { + std::make_tuple(invalid_key_label, 1, -1, "", ""), + std::make_tuple(invalid_value_label, 1, -1, "", ""), + }; + + if (!is_selinux_enabled()) { + SUCCEED() << "WARNING: The current machine does not support SELinux"; + return; + } + + for (const auto &elem : normal) { + char *process_label = nullptr; + char *mount_label = nullptr; + + ASSERT_EQ(init_label(std::get<0>(elem), std::get<1>(elem), &process_label, &mount_label), std::get<2>(elem)); + ASSERT_STREQ(process_label, nullptr); + ASSERT_STREQ(mount_label, nullptr); + } +} + +TEST(SELinuxLabelUnitTestWithoutMock, test_dup_security_opt) +{ + const char *label = "system_u:object_r:container_file_t:s0"; + char **dst = nullptr; + size_t len; + + ASSERT_EQ(dup_security_opt(label, &dst, &len), 0); + ASSERT_EQ(len, 4); + ASSERT_STREQ(dst[0], "user:system_u"); + ASSERT_STREQ(dst[1], "role:object_r"); + ASSERT_STREQ(dst[2], "type:container_file_t"); + ASSERT_STREQ(dst[3], "level:s0"); + util_free_array(dst); + dst = nullptr; + len = 0; + + ASSERT_EQ(dup_security_opt(nullptr, &dst, &len), 0); + ASSERT_EQ(dst, nullptr); +} + +class SELinuxRelabelUnitTest : public testing::Test { +protected: + void SetUp() override + { + CreateTestedObjects(); + } + + void TearDown() override + { + ClearTestedObjects(); + } + +private: + void CreateTestedObjects() + { + struct stat st; + + if (lstat(m_testDir.c_str(), &st) < 0) { + (void)mkdir(m_testDir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRWXG | S_IRWXO); + } + + ofstream osm; + osm.open(m_testFile); + osm << "SELinux unit test"; + osm.close(); + } + + void ClearTestedObjects() + { + remove(m_testFile.c_str()); + rmdir(m_testDir.c_str()); + } + +protected: + std::string m_testDir { "./test_dir" }; + std::string m_testFile { m_testDir + "/file" }; +}; + +TEST_F(SELinuxRelabelUnitTest, test_relabel_normal) +{ + std::vector> normal { + std::make_tuple("system_u:object_r:container_file_t:s0:c100,c200", false, 0, "system_u:object_r:container_file_t:s0:c100,c200"), + std::make_tuple("system_u:object_r:container_file_t:s0:c300,c300", false, 0, "system_u:object_r:container_file_t:s0:c300"), + std::make_tuple("system_u:object_r:container_file_t:s0:c100,c200", true, 0, "system_u:object_r:container_file_t:s0"), + std::make_tuple("system_u:object_r:container_file_t:s0:c300,c300", true, 0, "system_u:object_r:container_file_t:s0"), + }; + + if (!is_selinux_enabled()) { + SUCCEED() << "WARNING: The current machine does not support SELinux"; + return; + } + + for (const auto &elem : normal) { + char *context = nullptr; + + ASSERT_EQ(relabel(m_testDir.c_str(), std::get<0>(elem).c_str(), std::get<1>(elem)), std::get<2>(elem)); + ASSERT_GE(lgetfilecon(m_testFile.c_str(), &context), 0); + ASSERT_STREQ(context, std::get<3>(elem).c_str()); + freecon(context); + } +} + +TEST_F(SELinuxRelabelUnitTest, test_relabel_abnormal) +{ + std::vector> abnormal { + // exclude path test + std::make_tuple("/", "system_u:object_r:root_t:s0", true, -1), + std::make_tuple("/usr", "system_u:object_r:usr_t:s0", true, -1), + std::make_tuple("/etc", "system_u:object_r:etc_t:s0", true, -1), + std::make_tuple("/tmp", "system_u:object_r:tmp_t:s0", true, -1), + std::make_tuple("/home", "system_u:object_r:home_root_t:s0", true, -1), + std::make_tuple("/run", "system_u:object_r:var_run_t:s0", true, -1), + std::make_tuple("/var", "system_u:object_r:var_t:s0", true, -1), + std::make_tuple("/root", "system_u:object_r:admin_home_t:s0", true, -1), + // bad prefix test + std::make_tuple("/usr/xxx", "system_u:object_r:usr_t:s0", true, -1), + }; + + if (!is_selinux_enabled()) { + SUCCEED() << "WARNING: The current machine does not support SELinux"; + return; + } + + for (const auto &elem : abnormal) { + ASSERT_EQ(relabel(std::get<0>(elem).c_str(), std::get<1>(elem).c_str(), std::get<2>(elem)), std::get<3>(elem)); + } +} + +TEST_F(SELinuxRelabelUnitTest, test_get_disable_security_opt) +{ + char **labels = nullptr; + size_t labels_len; + + ASSERT_EQ(get_disable_security_opt(&labels, &labels_len), 0); + ASSERT_EQ(labels_len, 1); + ASSERT_NE(labels[0], "label=disable"); + + util_free_array(labels); +} + diff --git a/test/services/execution/spec/selinux_label_mock_llt.cc b/test/services/execution/spec/selinux_label_mock_llt.cc new file mode 100644 index 0000000..da719bd --- /dev/null +++ b/test/services/execution/spec/selinux_label_mock_llt.cc @@ -0,0 +1,68 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Author: wujing + * Create: 2020-02-14 + * Description: provide selinux label unit test + ******************************************************************************/ + +#include "selinux_label.h" +#include +#include +#include "selinux_mock.h" +#include "syscall_mock.h" + +using namespace std; +using ::testing::DoAll; +using ::testing::SetArgPointee; +using ::testing::ByRef; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::_; + +class SELinuxGetEnableUnitTest : public testing::Test { +public: + void SetUp() override + { + Selinux_SetMock(&m_selinux); + Syscall_SetMock(&m_syscall); + selinux_state_init(); + } + void TearDown() override + { + Selinux_SetMock(nullptr); + Syscall_SetMock(nullptr); + } + NiceMock m_selinux; + NiceMock m_syscall; +}; + +TEST_F(SELinuxGetEnableUnitTest, test_selinux_get_enable_abnormal) +{ + EXPECT_CALL(m_syscall, Statfs(_, _)).WillRepeatedly(Return(EPERM)); + EXPECT_CALL(m_selinux, SelinuxfsExists()).WillOnce(Return(-1)); + ASSERT_EQ(selinux_get_enable(), false); +} + +TEST_F(SELinuxGetEnableUnitTest, test_selinux_get_enable_normal) +{ + const uint32_t selinuxfsMagic = 0xf97cff8c; + struct statfs sfbuf { + .f_type = selinuxfsMagic, + .f_flags = 0 + }; + + EXPECT_CALL(m_syscall, Statfs(_, _)) + .WillOnce(Return(EPERM)) + .WillOnce(DoAll(SetArgPointee<1>(ByRef(sfbuf)), Return(0))); + EXPECT_CALL(m_selinux, SelinuxfsExists()).WillOnce(Return(-1)); + ASSERT_EQ(selinux_get_enable(), true); +} + diff --git a/test/services/graphdriver/CMakeLists.txt b/test/services/graphdriver/CMakeLists.txt new file mode 100644 index 0000000..49f78e6 --- /dev/null +++ b/test/services/graphdriver/CMakeLists.txt @@ -0,0 +1,3 @@ +project(iSulad_LLT) + +add_subdirectory(driver) diff --git a/test/services/graphdriver/driver/CMakeLists.txt b/test/services/graphdriver/driver/CMakeLists.txt new file mode 100644 index 0000000..b17a489 --- /dev/null +++ b/test/services/graphdriver/driver/CMakeLists.txt @@ -0,0 +1,48 @@ +project(iSulad_LLT) + +SET(EXE driver_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/driver_overlay2_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/image_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/isulad_config_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/graphdriver/driver.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/graphdriver/devmapper/driver_devmapper.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libisulad.c + ${CMAKE_BINARY_DIR}/json/json_common.c + driver_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/json + ${ENGINES_INCS} + ${RUNTIME_INCS} + ${IMAGE_INCS} + ${CMAKE_BINARY_DIR}/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/graphdriver/devmapper + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/graphdriver + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/services/graphdriver/overlay2 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/image + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks + ) + +#set_target_properties(${EXE} PROPERTIES LINK_FLAGS) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/services/graphdriver/driver/driver_llt.cc b/test/services/graphdriver/driver/driver_llt.cc new file mode 100644 index 0000000..76f53f8 --- /dev/null +++ b/test/services/graphdriver/driver/driver_llt.cc @@ -0,0 +1,162 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Description: driver llt + * Author: wangfengtu + * Create: 2020-02-19 + */ + +#include +#include +#include +#include "mock.h" +#include +#include +#include "utils.h" +#include "driver_devmapper.h" +#include "image.h" +#include "image_mock.h" +#include "driver_overlay2_mock.h" +#include "isulad_config_mock.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class DriverUnitTest : public testing::Test { +public: + void SetUp() override + { + MockImage_SetMock(&m_image); + MockIsuladConf_SetMock(&m_isulad_config); + MockDriverOverlay2_SetMock(&m_driver_overlay2); + ::testing::Mock::AllowLeak(&m_image); + ::testing::Mock::AllowLeak(&m_isulad_config); + ::testing::Mock::AllowLeak(&m_driver_overlay2); + } + void TearDown() override + { + MockImage_SetMock(nullptr); + MockIsuladConf_SetMock(nullptr); + MockDriverOverlay2_SetMock(nullptr); + } + + NiceMock m_image; + NiceMock m_isulad_config; + NiceMock m_driver_overlay2; +}; + +// All parameter NULL +TEST(graphdriver_init_llt, test_graphdriver_init_1) +{ + ASSERT_TRUE(graphdriver_init(NULL, NULL, 0) == NULL); +} + +// All parameter correct +TEST(graphdriver_init_llt, test_graphdriver_init_2) +{ + struct graphdriver *driver = NULL; + char **options = NULL; + size_t options_len = 0; + + options = util_string_split("dm.fs=ext4#dm.thinpooldev=/dev/mapper/isula-thinpool#" + "dm.min_free_space=10%#dm.basesize=5G#dm.mountopt=nodiscard#" + "dm.mkfsarg=-O ^has_journal#dm.mountopt=nodiscard", '#'); + options_len = util_array_len((const char**)options); + driver = graphdriver_init("devicemapper", options, options_len); + ASSERT_TRUE(driver != NULL); + ASSERT_EQ(driver->name, "devicemapper"); + util_free_array(options); +} + +// Parameter dm.fs invalid +TEST(graphdriver_init_llt, test_graphdriver_init_3) +{ + struct graphdriver *driver = NULL; + char **options = NULL; + size_t options_len = 0; + + options = util_string_split("dm.fs=xfs", ' '); + options_len = util_array_len((const char**)options); + driver = graphdriver_init("devicemapper", options, options_len); + ASSERT_TRUE(driver == NULL); + util_free_array(options); +} + +// Parameter dm.thinpooldev invalid +TEST(graphdriver_init_llt, test_graphdriver_init_4) +{ + struct graphdriver *driver = NULL; + char **options = NULL; + size_t options_len = 0; + + options = util_string_split("dm.thinpooldev=", ' '); + options_len = util_array_len((const char**)options); + driver = graphdriver_init("devicemapper", options, options_len); + ASSERT_TRUE(driver == NULL); + util_free_array(options); +} + +// Parameter dm.min_free_space invalid +TEST(graphdriver_init_llt, test_graphdriver_init_5) +{ + struct graphdriver *driver = NULL; + char **options = NULL; + size_t options_len = 0; + + options = util_string_split("dm.min_free_space=101%", ' '); + options_len = util_array_len((const char**)options); + driver = graphdriver_init("devicemapper", options, options_len); + ASSERT_TRUE(driver == NULL); + util_free_array(options); + + options = util_string_split("dm.min_free_space=100%", ' '); + options_len = util_array_len((const char**)options); + driver = graphdriver_init("devicemapper", options, options_len); + ASSERT_TRUE(driver == NULL); + util_free_array(options); +} + +// Parameter dm.basesize invalid +TEST(graphdriver_init_llt, test_graphdriver_init_6) +{ + struct graphdriver *driver = NULL; + char **options = NULL; + size_t options_len = 0; + + options = util_string_split("dm.basesize=-1", ' '); + options_len = util_array_len((const char**)options); + driver = graphdriver_init("devicemapper", options, options_len); + ASSERT_TRUE(driver == NULL); + util_free_array(options); +} + +// None exist parameter +TEST(graphdriver_init_llt, test_graphdriver_init_7) +{ + struct graphdriver *driver = NULL; + char **options = NULL; + size_t options_len = 0; + + options = util_string_split("kkkk=aaa", ' '); + options_len = util_array_len((const char**)options); + driver = graphdriver_init("devicemapper", options, options_len); + ASSERT_TRUE(driver == NULL); + util_free_array(options); +} diff --git a/test/specs/CMakeLists.txt b/test/specs/CMakeLists.txt new file mode 100644 index 0000000..1281797 --- /dev/null +++ b/test/specs/CMakeLists.txt @@ -0,0 +1,4 @@ +project(iSulad_LLT) + +add_subdirectory(specs) +add_subdirectory(specs_extend) diff --git a/test/specs/specs/CMakeLists.txt b/test/specs/specs/CMakeLists.txt new file mode 100644 index 0000000..1d8e981 --- /dev/null +++ b/test/specs/specs/CMakeLists.txt @@ -0,0 +1,84 @@ +project(iSulad_LLT) + +SET(EXE specs_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/sha256/sha256.c + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/specs.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/specs_mount.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/specs_extend.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/specs_security.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/oci_runtime_hooks.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/parse_common.c + ${CMAKE_BINARY_DIR}/json/defs.c + ${CMAKE_BINARY_DIR}/json/container_config_v2.c + ${CMAKE_BINARY_DIR}/json/container_config.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_spec.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/sysinfo.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_config_linux.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/commander.c + ${CMAKE_BINARY_DIR}/json/isulad_daemon_configs.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad/arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/image/oci/oci_llt_common.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/containers_store_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/namespace_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/container_unix_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/engine_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/selinux_label_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/isulad_config_mock.cc + ${CMAKE_BINARY_DIR}/json/imagetool_image.c + ${CMAKE_BINARY_DIR}/json/oci_image_spec.c + ${CMAKE_BINARY_DIR}/json/docker_seccomp.c + specs_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/image + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/events + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/execute + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/tar + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/plugin + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/http + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/engines + ${ENGINES_INCS} + #${EXECUTION_INCS} + ${RUNTIME_INCS} + ${IMAGE_INCS} + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/graphdriver + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks + ) + +#set_target_properties(${EXE} PROPERTIES LINK_FLAGS) +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/specs/specs/hostconfig.json b/test/specs/specs/hostconfig.json new file mode 100644 index 0000000..41255d6 --- /dev/null +++ b/test/specs/specs/hostconfig.json @@ -0,0 +1,6 @@ +{ + "ShmSize": 67108864, + "RestartPolicy": { + "Name": "no" + } +} diff --git a/test/specs/specs/oci_runtime_spec.json b/test/specs/specs/oci_runtime_spec.json new file mode 100644 index 0000000..cdc3a4e --- /dev/null +++ b/test/specs/specs/oci_runtime_spec.json @@ -0,0 +1,741 @@ +{ + "ociVersion": "1.0.0-rc5-dev", + "hooks": { + + }, + "annotations": { + "log.console.file": "none", + "log.console.filerotate": "7", + "log.console.filesize": "1MB", + "rootfs.mount": "/var/lib/lcrd/mnt/rootfs", + "native.umask": "secure" + }, + "hostname": "localhost", + "mounts": [ + { + "source": "proc", + "destination": "/proc", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "type": "proc" + }, + { + "source": "tmpfs", + "destination": "/dev", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ], + "type": "tmpfs" + }, + { + "source": "devpts", + "destination": "/dev/pts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ], + "type": "devpts" + }, + { + "source": "sysfs", + "destination": "/sys", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ], + "type": "sysfs" + }, + { + "source": "shm", + "destination": "/dev/shm", + "options": [ + "nosuid", + "noexec", + "nodev", + "mode=1777", + "size=67108864" + ], + "type": "tmpfs" + }, + { + "source": "cgroup", + "destination": "/sys/fs/cgroup", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ], + "type": "cgroup" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "type": "mqueue" + }, + { + "source": "/var/lib/lcrd/engines/lcr/ad6c3f33518ed7e17a6d889a1327aa386f8b869927e2540821fb02310f567310/hostname", + "destination": "/etc/hostname", + "options": [ + "rbind", + "rprivate" + ], + "type": "bind" + }, + { + "source": "/var/lib/lcrd/engines/lcr/ad6c3f33518ed7e17a6d889a1327aa386f8b869927e2540821fb02310f567310/resolv.conf", + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rprivate" + ], + "type": "bind" + }, + { + "source": "/var/lib/lcrd/engines/lcr/ad6c3f33518ed7e17a6d889a1327aa386f8b869927e2540821fb02310f567310/hosts", + "destination": "/etc/hosts", + "options": [ + "rbind", + "rprivate" + ], + "type": "bind" + } + ], + "root": { + "path": "/var/lib/lcrd/storage/overlay/40c51530fc1b4610f7f56633ef78fc5e4ad1a6f14cad59d5a1d012ff800c4289/merged" + }, + "process": { + "args": [ + "sh" + ], + "consoleSize": { + + }, + "cwd": "/", + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm", + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "terminal": true, + "user": { + + }, + "capabilities": { + "bounding": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ] + } + }, + "linux": { + "namespaces": [ + { + "type": "pid" + }, + { + "type": "network" + }, + { + "type": "ipc" + }, + { + "type": "uts" + }, + { + "type": "mount" + } + ], + "resources": { + "devices": [ + { + "type": "a", + "major": -1, + "minor": -1, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": -1, + "minor": -1, + "access": "m" + }, + { + "allow": true, + "type": "b", + "major": -1, + "minor": -1, + "access": "m" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 3, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 5, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 7, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 5, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 5, + "minor": 1, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 5, + "minor": 2, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 8, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 9, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 136, + "minor": -1, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 10, + "minor": 200, + "access": "rwm" + }, + { + "type": "c", + "major": 10, + "minor": 229, + "access": "rwm" + } + ] + }, + "seccomp": { + "defaultAction": "SCMP_ACT_ERRNO", + "architectures": [ + "SCMP_ARCH_X86_64", + "SCMP_ARCH_X86", + "SCMP_ARCH_X32", + "SCMP_ARCH_AARCH64", + "SCMP_ARCH_ARM" + ], + "syscalls": [ + { + "names": [ + "accept", + "accept4", + "access", + "adjtimex", + "alarm", + "bind", + "brk", + "capget", + "capset", + "chdir", + "chmod", + "chown", + "chown32", + "clock_getres", + "clock_gettime", + "clock_nanosleep", + "close", + "connect", + "copy_file_range", + "creat", + "dup", + "dup2", + "dup3", + "epoll_create", + "epoll_create1", + "epoll_ctl", + "epoll_ctl_old", + "epoll_pwait", + "epoll_wait", + "epoll_wait_old", + "eventfd", + "eventfd2", + "execve", + "execveat", + "exit", + "exit_group", + "faccessat", + "fadvise64", + "fadvise64_64", + "fallocate", + "fanotify_mark", + "fchdir", + "fchmod", + "fchmodat", + "fchown", + "fchown32", + "fchownat", + "fcntl", + "fcntl64", + "fdatasync", + "fgetxattr", + "flistxattr", + "flock", + "fork", + "fremovexattr", + "fsetxattr", + "fstat", + "fstat64", + "fstatat64", + "fstatfs", + "fstatfs64", + "fsync", + "ftruncate", + "ftruncate64", + "futex", + "futimesat", + "getcpu", + "getcwd", + "getdents", + "getdents64", + "getegid", + "getegid32", + "geteuid", + "geteuid32", + "getgid", + "getgid32", + "getgroups", + "getgroups32", + "getitimer", + "getpeername", + "getpgid", + "getpgrp", + "getpid", + "getppid", + "getpriority", + "getrandom", + "getresgid", + "getresgid32", + "getresuid", + "getresuid32", + "getrlimit", + "get_robust_list", + "getrusage", + "getsid", + "getsockname", + "getsockopt", + "get_thread_area", + "gettid", + "gettimeofday", + "getuid", + "getuid32", + "getxattr", + "inotify_add_watch", + "inotify_init", + "inotify_init1", + "inotify_rm_watch", + "io_cancel", + "ioctl", + "io_destroy", + "io_getevents", + "ioprio_get", + "ioprio_set", + "io_setup", + "io_submit", + "ipc", + "kill", + "lchown", + "lchown32", + "lgetxattr", + "link", + "linkat", + "listen", + "listxattr", + "llistxattr", + "_llseek", + "lremovexattr", + "lseek", + "lsetxattr", + "lstat", + "lstat64", + "madvise", + "memfd_create", + "mincore", + "mkdir", + "mkdirat", + "mknod", + "mknodat", + "mlock", + "mlock2", + "mlockall", + "mmap", + "mmap2", + "mprotect", + "mq_getsetattr", + "mq_notify", + "mq_open", + "mq_timedreceive", + "mq_timedsend", + "mq_unlink", + "mremap", + "msgctl", + "msgget", + "msgrcv", + "msgsnd", + "msync", + "munlock", + "munlockall", + "munmap", + "nanosleep", + "newfstatat", + "_newselect", + "open", + "openat", + "pause", + "pipe", + "pipe2", + "poll", + "ppoll", + "prctl", + "pread64", + "preadv", + "preadv2", + "prlimit64", + "pselect6", + "pwrite64", + "pwritev", + "pwritev2", + "read", + "readahead", + "readlink", + "readlinkat", + "readv", + "recv", + "recvfrom", + "recvmmsg", + "recvmsg", + "remap_file_pages", + "removexattr", + "rename", + "renameat", + "renameat2", + "restart_syscall", + "rmdir", + "rt_sigaction", + "rt_sigpending", + "rt_sigprocmask", + "rt_sigqueueinfo", + "rt_sigreturn", + "rt_sigsuspend", + "rt_sigtimedwait", + "rt_tgsigqueueinfo", + "sched_getaffinity", + "sched_getattr", + "sched_getparam", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_getscheduler", + "sched_rr_get_interval", + "sched_setaffinity", + "sched_setattr", + "sched_setparam", + "sched_setscheduler", + "sched_yield", + "seccomp", + "select", + "semctl", + "semget", + "semop", + "semtimedop", + "send", + "sendfile", + "sendfile64", + "sendmmsg", + "sendmsg", + "sendto", + "setfsgid", + "setfsgid32", + "setfsuid", + "setfsuid32", + "setgid", + "setgid32", + "setgroups", + "setgroups32", + "setitimer", + "setpgid", + "setpriority", + "setregid", + "setregid32", + "setresgid", + "setresgid32", + "setresuid", + "setresuid32", + "setreuid", + "setreuid32", + "setrlimit", + "set_robust_list", + "setsid", + "setsockopt", + "set_thread_area", + "set_tid_address", + "setuid", + "setuid32", + "setxattr", + "shmat", + "shmctl", + "shmdt", + "shmget", + "shutdown", + "sigaltstack", + "signalfd", + "signalfd4", + "sigreturn", + "socket", + "socketcall", + "socketpair", + "splice", + "stat", + "stat64", + "statfs", + "statfs64", + "statx", + "symlink", + "symlinkat", + "sync", + "sync_file_range", + "syncfs", + "sysinfo", + "tee", + "tgkill", + "time", + "timer_create", + "timer_delete", + "timerfd_create", + "timerfd_gettime", + "timerfd_settime", + "timer_getoverrun", + "timer_gettime", + "timer_settime", + "times", + "tkill", + "truncate", + "truncate64", + "ugetrlimit", + "umask", + "uname", + "unlink", + "unlinkat", + "utime", + "utimensat", + "utimes", + "vfork", + "vmsplice", + "wait4", + "waitid", + "waitpid", + "write", + "writev" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "ptrace" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 8, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 131072, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 131080, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 4294967295, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "arm_fadvise64_64", + "arm_sync_file_range", + "sync_file_range2", + "breakpoint", + "cacheflush", + "set_tls" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "arch_prctl" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "modify_ldt" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "clone" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 2080505856, + "op": "SCMP_CMP_MASKED_EQ" + } + ] + }, + { + "names": [ + "chroot" + ], + "action": "SCMP_ACT_ALLOW" + } + ] + }, + "maskedPaths": [ + "/proc/acpi", + "/proc/config.gz", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/proc/signo", + "/proc/sig_catch", + "/proc/kbox", + "/proc/oom_extend", + "/proc/fdthreshold", + "/proc/fdstat", + "/proc/fdenable", + "/proc/files_panic_enable", + "/sys/firmware", + "/proc/cpuirqstat", + "/proc/memstat", + "/proc/iomem_ext", + "/proc/livepatch" + ], + "readonlyPaths": [ + "/proc/asound", + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger", + "/proc/sysrq-region-size" + ] + } +} diff --git a/test/specs/specs/specs_llt.cc b/test/specs/specs/specs_llt.cc new file mode 100644 index 0000000..66ca319 --- /dev/null +++ b/test/specs/specs/specs_llt.cc @@ -0,0 +1,337 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Description: specs llt + * Author: lifeng + * Create: 2020-02-18 + */ + +#include +#include +#include +#include "mock.h" +#include "oci_runtime_spec.h" +#include "specs.h" +#include "host_config.h" +#include "container_config.h" +#include "oci_llt_common.h" +#include +#include +#include "isulad_config_mock.h" +#include "utils.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +class SpecsUnitTest : public testing::Test { +public: + void SetUp() override + { + MockIsuladConf_SetMock(&m_isulad_conf); + ::testing::Mock::AllowLeak(&m_isulad_conf); + } + void TearDown() override + { + MockIsuladConf_SetMock(nullptr); + } + + NiceMock m_isulad_conf; +}; + +#define HOST_CONFIG_FILE "specs/specs/hostconfig.json" +#define OCI_RUNTIME_SPEC_FILE "specs/specs/oci_runtime_spec.json" + +TEST(merge_conf_cgroup_llt, test_merge_conf_cgroup_1) +{ + // All parameter NULL + ASSERT_NE(merge_conf_cgroup(NULL, NULL), 0); +} + +TEST(merge_conf_cgroup_llt, test_merge_conf_cgroup_2) +{ + oci_runtime_spec *oci_spec = NULL; + + // Parameter host_spec is NULL + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + ASSERT_NE(merge_conf_cgroup(oci_spec, NULL), 0); + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(merge_conf_cgroup_llt, test_merge_conf_cgroup_3) +{ + char *host_config_file = NULL; + host_config *host_spec = NULL; + char *err = NULL; + + // Parameter oci_spec is NULL + host_config_file = json_path(HOST_CONFIG_FILE); + ASSERT_TRUE(host_config_file != NULL); + host_spec = host_config_parse_file(host_config_file, NULL, &err); + ASSERT_TRUE(host_spec != NULL); + free(err); + err = NULL; + free(host_config_file); + host_config_file = NULL; + ASSERT_NE(merge_conf_cgroup(NULL, host_spec), 0); + free_host_config(host_spec); + host_spec = NULL; +} + +TEST(merge_conf_cgroup_llt, test_merge_conf_cgroup) +{ + char *host_config_file = NULL; + host_config *host_spec = NULL; + oci_runtime_spec *oci_spec = NULL; + char *err = NULL; + + // All parameter correct + host_config_file = json_path(HOST_CONFIG_FILE); + ASSERT_TRUE(host_config_file != NULL); + host_spec = host_config_parse_file(host_config_file, NULL, &err); + ASSERT_TRUE(host_spec != NULL); + free(err); + err = NULL; + free(host_config_file); + host_config_file = NULL; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + + ASSERT_EQ(merge_conf_cgroup(oci_spec, host_spec), 0); + + free_host_config(host_spec); + host_spec = NULL; + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(merge_conf_cgroup_llt, test_merge_conf_cgroup_cpu) +{ + char *host_config_file = NULL; + host_config *host_spec = NULL; + char *oci_config_file = NULL; + oci_runtime_spec *oci_spec = NULL; + char *err = NULL; + + // cpu + host_config_file = json_path(HOST_CONFIG_FILE); + ASSERT_TRUE(host_config_file != NULL); + host_spec = host_config_parse_file(host_config_file, NULL, &err); + ASSERT_TRUE(host_spec != NULL); + free(err); + err = NULL; + free(host_config_file); + host_config_file = NULL; + + oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); + ASSERT_TRUE(oci_config_file != NULL); + oci_spec = oci_runtime_spec_parse_file(oci_config_file, NULL, &err); + ASSERT_TRUE(oci_spec != NULL); + free(err); + err = NULL; + free(oci_config_file); + oci_config_file = NULL; + + host_spec->cpu_period = 123; + host_spec->cpu_quota = 234; + host_spec->cpu_realtime_period = 456; + host_spec->cpu_realtime_runtime = 789; + host_spec->cpu_shares = 321; + free(host_spec->cpuset_cpus); + host_spec->cpuset_cpus = util_strdup_s("0-3"); + free(host_spec->cpuset_mems); + host_spec->cpuset_mems = util_strdup_s("0"); + + ASSERT_EQ(merge_conf_cgroup(oci_spec, host_spec), 0); + + ASSERT_EQ(oci_spec->linux->resources->cpu->period, 123); + ASSERT_EQ(oci_spec->linux->resources->cpu->quota, 234); + ASSERT_EQ(oci_spec->linux->resources->cpu->realtime_period, 456); + ASSERT_EQ(oci_spec->linux->resources->cpu->realtime_runtime, 789); + ASSERT_EQ(oci_spec->linux->resources->cpu->shares, 321); + ASSERT_STREQ(oci_spec->linux->resources->cpu->cpus, "0-3"); + ASSERT_STREQ(oci_spec->linux->resources->cpu->mems, "0"); + + free_host_config(host_spec); + host_spec = NULL; + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(merge_conf_cgroup_llt, test_merge_conf_cgroup_mem) +{ + char *host_config_file = NULL; + host_config *host_spec = NULL; + char *oci_config_file = NULL; + oci_runtime_spec *oci_spec = NULL; + char *err = NULL; + + // mem + // int64_t kernel_memory; + // int64_t memory_reservation; + // int64_t memory_swap; + host_config_file = json_path(HOST_CONFIG_FILE); + ASSERT_TRUE(host_config_file != NULL); + host_spec = host_config_parse_file(host_config_file, NULL, &err); + ASSERT_TRUE(host_spec != NULL); + free(err); + err = NULL; + free(host_config_file); + host_config_file = NULL; + + oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); + ASSERT_TRUE(oci_config_file != NULL); + oci_spec = oci_runtime_spec_parse_file(oci_config_file, NULL, &err); + ASSERT_TRUE(oci_spec != NULL); + free(err); + err = NULL; + free(oci_config_file); + oci_config_file = NULL; + + host_spec->kernel_memory = 123; + host_spec->memory_reservation = 234; + host_spec->memory_swap = 456; + + ASSERT_EQ(merge_conf_cgroup(oci_spec, host_spec), 0); + + ASSERT_EQ(oci_spec->linux->resources->memory->kernel, 123); + ASSERT_EQ(oci_spec->linux->resources->memory->reservation, 234); + ASSERT_EQ(oci_spec->linux->resources->memory->swap, 456); + + free_host_config(host_spec); + host_spec = NULL; + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +/* conf get routine rootdir */ +char *invoke_conf_get_isulad_cgroup_parent_null() +{ + return nullptr; +} + +/* conf get routine rootdir */ +char *invoke_conf_get_isulad_cgroup_parent() +{ + return util_strdup_s("/var/lib/isulad/engines/lcr"); +} + +TEST_F(SpecsUnitTest, test_merge_oci_cgroups_path_1) +{ + ASSERT_EQ(merge_oci_cgroups_path(nullptr, nullptr, nullptr), -1); +} + +TEST_F(SpecsUnitTest, test_merge_oci_cgroups_path_2) +{ + oci_runtime_spec *oci_spec = nullptr; + host_config *host_spec = nullptr; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + + host_spec = (host_config *) util_common_calloc_s(sizeof(host_config)); + ASSERT_TRUE(host_spec != NULL); + + EXPECT_CALL(m_isulad_conf, GetCgroupParent()).WillRepeatedly(Invoke(invoke_conf_get_isulad_cgroup_parent_null)); + + ASSERT_EQ(merge_oci_cgroups_path("123", oci_spec, host_spec), 0); + + ASSERT_STREQ(oci_spec->linux->cgroups_path, "/isulad/123"); + + free_oci_runtime_spec(oci_spec); + free_host_config(host_spec); + + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(SpecsUnitTest, test_merge_oci_cgroups_path_3) +{ + oci_runtime_spec *oci_spec = nullptr; + host_config *host_spec = nullptr; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + + host_spec = (host_config *) util_common_calloc_s(sizeof(host_config)); + ASSERT_TRUE(host_spec != NULL); + + host_spec->cgroup_parent = util_strdup_s("/test"); + + EXPECT_CALL(m_isulad_conf, GetCgroupParent()).WillRepeatedly(Invoke(invoke_conf_get_isulad_cgroup_parent_null)); + + ASSERT_EQ(merge_oci_cgroups_path("123", oci_spec, host_spec), 0); + + ASSERT_STREQ(oci_spec->linux->cgroups_path, "/test/123"); + + free_oci_runtime_spec(oci_spec); + free_host_config(host_spec); + + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(SpecsUnitTest, test_merge_oci_cgroups_path_4) +{ + oci_runtime_spec *oci_spec = nullptr; + host_config *host_spec = nullptr; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + + host_spec = (host_config *) util_common_calloc_s(sizeof(host_config)); + ASSERT_TRUE(host_spec != NULL); + + EXPECT_CALL(m_isulad_conf, GetCgroupParent()).WillRepeatedly(Invoke(invoke_conf_get_isulad_cgroup_parent)); + + ASSERT_EQ(merge_oci_cgroups_path("123", oci_spec, host_spec), 0); + + ASSERT_STREQ(oci_spec->linux->cgroups_path, "/var/lib/isulad/engines/lcr/123"); + + free_oci_runtime_spec(oci_spec); + free_host_config(host_spec); + + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} + +TEST_F(SpecsUnitTest, test_merge_oci_cgroups_path_5) +{ + oci_runtime_spec *oci_spec = nullptr; + host_config *host_spec = nullptr; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + + host_spec = (host_config *) util_common_calloc_s(sizeof(host_config)); + ASSERT_TRUE(host_spec != NULL); + + host_spec->cgroup_parent = util_strdup_s("/test"); + + EXPECT_CALL(m_isulad_conf, GetCgroupParent()).WillRepeatedly(Invoke(invoke_conf_get_isulad_cgroup_parent)); + + ASSERT_EQ(merge_oci_cgroups_path("123", oci_spec, host_spec), 0); + + ASSERT_STREQ(oci_spec->linux->cgroups_path, "/test/123"); + + free_oci_runtime_spec(oci_spec); + free_host_config(host_spec); + + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); +} diff --git a/test/specs/specs_extend/CMakeLists.txt b/test/specs/specs_extend/CMakeLists.txt new file mode 100644 index 0000000..197352c --- /dev/null +++ b/test/specs/specs_extend/CMakeLists.txt @@ -0,0 +1,82 @@ +project(iSulad_LLT) + +SET(EXE specs_extend_llt) + +add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_verify.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/log.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/sha256/sha256.c + ${CMAKE_BINARY_DIR}/json/json_common.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/specs.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/specs_mount.c + ${CMAKE_BINARY_DIR}/json/host_config.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/specs_extend.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/specs_security.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/libisulad.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/oci_runtime_hooks.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/parse_common.c + ${CMAKE_BINARY_DIR}/json/defs.c + ${CMAKE_BINARY_DIR}/json/container_config_v2.c + ${CMAKE_BINARY_DIR}/json/container_config.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_spec.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec/sysinfo.c + ${CMAKE_BINARY_DIR}/json/oci_runtime_config_linux.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/commander.c + ${CMAKE_BINARY_DIR}/json/isulad_daemon_configs.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src/read_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad/arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/image/oci/oci_llt_common.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/containers_store_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/namespace_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/container_unix_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/engine_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/selinux_label_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/isulad_config_mock.cc + ${CMAKE_BINARY_DIR}/json/imagetool_image.c + ${CMAKE_BINARY_DIR}/json/oci_image_spec.c + ${CMAKE_BINARY_DIR}/json/docker_seccomp.c + specs_extend_llt.cc) + +target_include_directories(${EXE} PUBLIC + ${GTEST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../include + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/image + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cutils + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/spec + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/events + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/execution/execute + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/tar + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/plugin + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/http + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/engines + ${ENGINES_INCS} + ${RUNTIME_INCS} + ${IMAGE_INCS} + ${CMAKE_BINARY_DIR}/json + ${CMAKE_BINARY_DIR}/conf + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/services/graphdriver + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/json/schema/src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/console + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks + ) + +target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} -lgrpc++ -lprotobuf -lcrypto -lyajl -lz) diff --git a/test/specs/specs_extend/hooks.json b/test/specs/specs_extend/hooks.json new file mode 100644 index 0000000..2a6d261 --- /dev/null +++ b/test/specs/specs_extend/hooks.json @@ -0,0 +1,38 @@ +{ + "prestart": [ + { + "path": "/home/hooks/start.bash", + "args": ["arg0", "arg1", "arg2"], + "timeout": 40, + "env": [ "key1=value1"] + } + ], + "poststart": [ + { + "path": "/home/hooks/post1.bash", + "args": ["arg5", "arg6", "arg7"], + "timeout": 60, + "env": [ "key2=value221"] + }, + { + "path": "/home/hooks/post2.bash", + "args": ["arg51", "arg61", "arg71"], + "timeout": 61, + "env": [ "key3=value3"] + } + ], + "poststop": [ + { + "path": "/home/hooks/stop1.bash", + "args": ["arg11", "arg12", "arg13"], + "timeout": 60, + "env": [ "key2=value221"] + }, + { + "path": "/home/hooks/stop2.bash", + "args": ["arg52", "arg62", "arg72"], + "timeout": 62, + "env": [ "key4=value4"] + } + ] +} diff --git a/test/specs/specs_extend/hostconfig.json b/test/specs/specs_extend/hostconfig.json new file mode 100644 index 0000000..41255d6 --- /dev/null +++ b/test/specs/specs_extend/hostconfig.json @@ -0,0 +1,6 @@ +{ + "ShmSize": 67108864, + "RestartPolicy": { + "Name": "no" + } +} diff --git a/test/specs/specs_extend/oci_runtime_spec.json b/test/specs/specs_extend/oci_runtime_spec.json new file mode 100644 index 0000000..cdc3a4e --- /dev/null +++ b/test/specs/specs_extend/oci_runtime_spec.json @@ -0,0 +1,741 @@ +{ + "ociVersion": "1.0.0-rc5-dev", + "hooks": { + + }, + "annotations": { + "log.console.file": "none", + "log.console.filerotate": "7", + "log.console.filesize": "1MB", + "rootfs.mount": "/var/lib/lcrd/mnt/rootfs", + "native.umask": "secure" + }, + "hostname": "localhost", + "mounts": [ + { + "source": "proc", + "destination": "/proc", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "type": "proc" + }, + { + "source": "tmpfs", + "destination": "/dev", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ], + "type": "tmpfs" + }, + { + "source": "devpts", + "destination": "/dev/pts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ], + "type": "devpts" + }, + { + "source": "sysfs", + "destination": "/sys", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ], + "type": "sysfs" + }, + { + "source": "shm", + "destination": "/dev/shm", + "options": [ + "nosuid", + "noexec", + "nodev", + "mode=1777", + "size=67108864" + ], + "type": "tmpfs" + }, + { + "source": "cgroup", + "destination": "/sys/fs/cgroup", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ], + "type": "cgroup" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "type": "mqueue" + }, + { + "source": "/var/lib/lcrd/engines/lcr/ad6c3f33518ed7e17a6d889a1327aa386f8b869927e2540821fb02310f567310/hostname", + "destination": "/etc/hostname", + "options": [ + "rbind", + "rprivate" + ], + "type": "bind" + }, + { + "source": "/var/lib/lcrd/engines/lcr/ad6c3f33518ed7e17a6d889a1327aa386f8b869927e2540821fb02310f567310/resolv.conf", + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rprivate" + ], + "type": "bind" + }, + { + "source": "/var/lib/lcrd/engines/lcr/ad6c3f33518ed7e17a6d889a1327aa386f8b869927e2540821fb02310f567310/hosts", + "destination": "/etc/hosts", + "options": [ + "rbind", + "rprivate" + ], + "type": "bind" + } + ], + "root": { + "path": "/var/lib/lcrd/storage/overlay/40c51530fc1b4610f7f56633ef78fc5e4ad1a6f14cad59d5a1d012ff800c4289/merged" + }, + "process": { + "args": [ + "sh" + ], + "consoleSize": { + + }, + "cwd": "/", + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm", + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "terminal": true, + "user": { + + }, + "capabilities": { + "bounding": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ] + } + }, + "linux": { + "namespaces": [ + { + "type": "pid" + }, + { + "type": "network" + }, + { + "type": "ipc" + }, + { + "type": "uts" + }, + { + "type": "mount" + } + ], + "resources": { + "devices": [ + { + "type": "a", + "major": -1, + "minor": -1, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": -1, + "minor": -1, + "access": "m" + }, + { + "allow": true, + "type": "b", + "major": -1, + "minor": -1, + "access": "m" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 3, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 5, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 7, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 5, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 5, + "minor": 1, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 5, + "minor": 2, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 8, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 9, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 136, + "minor": -1, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 10, + "minor": 200, + "access": "rwm" + }, + { + "type": "c", + "major": 10, + "minor": 229, + "access": "rwm" + } + ] + }, + "seccomp": { + "defaultAction": "SCMP_ACT_ERRNO", + "architectures": [ + "SCMP_ARCH_X86_64", + "SCMP_ARCH_X86", + "SCMP_ARCH_X32", + "SCMP_ARCH_AARCH64", + "SCMP_ARCH_ARM" + ], + "syscalls": [ + { + "names": [ + "accept", + "accept4", + "access", + "adjtimex", + "alarm", + "bind", + "brk", + "capget", + "capset", + "chdir", + "chmod", + "chown", + "chown32", + "clock_getres", + "clock_gettime", + "clock_nanosleep", + "close", + "connect", + "copy_file_range", + "creat", + "dup", + "dup2", + "dup3", + "epoll_create", + "epoll_create1", + "epoll_ctl", + "epoll_ctl_old", + "epoll_pwait", + "epoll_wait", + "epoll_wait_old", + "eventfd", + "eventfd2", + "execve", + "execveat", + "exit", + "exit_group", + "faccessat", + "fadvise64", + "fadvise64_64", + "fallocate", + "fanotify_mark", + "fchdir", + "fchmod", + "fchmodat", + "fchown", + "fchown32", + "fchownat", + "fcntl", + "fcntl64", + "fdatasync", + "fgetxattr", + "flistxattr", + "flock", + "fork", + "fremovexattr", + "fsetxattr", + "fstat", + "fstat64", + "fstatat64", + "fstatfs", + "fstatfs64", + "fsync", + "ftruncate", + "ftruncate64", + "futex", + "futimesat", + "getcpu", + "getcwd", + "getdents", + "getdents64", + "getegid", + "getegid32", + "geteuid", + "geteuid32", + "getgid", + "getgid32", + "getgroups", + "getgroups32", + "getitimer", + "getpeername", + "getpgid", + "getpgrp", + "getpid", + "getppid", + "getpriority", + "getrandom", + "getresgid", + "getresgid32", + "getresuid", + "getresuid32", + "getrlimit", + "get_robust_list", + "getrusage", + "getsid", + "getsockname", + "getsockopt", + "get_thread_area", + "gettid", + "gettimeofday", + "getuid", + "getuid32", + "getxattr", + "inotify_add_watch", + "inotify_init", + "inotify_init1", + "inotify_rm_watch", + "io_cancel", + "ioctl", + "io_destroy", + "io_getevents", + "ioprio_get", + "ioprio_set", + "io_setup", + "io_submit", + "ipc", + "kill", + "lchown", + "lchown32", + "lgetxattr", + "link", + "linkat", + "listen", + "listxattr", + "llistxattr", + "_llseek", + "lremovexattr", + "lseek", + "lsetxattr", + "lstat", + "lstat64", + "madvise", + "memfd_create", + "mincore", + "mkdir", + "mkdirat", + "mknod", + "mknodat", + "mlock", + "mlock2", + "mlockall", + "mmap", + "mmap2", + "mprotect", + "mq_getsetattr", + "mq_notify", + "mq_open", + "mq_timedreceive", + "mq_timedsend", + "mq_unlink", + "mremap", + "msgctl", + "msgget", + "msgrcv", + "msgsnd", + "msync", + "munlock", + "munlockall", + "munmap", + "nanosleep", + "newfstatat", + "_newselect", + "open", + "openat", + "pause", + "pipe", + "pipe2", + "poll", + "ppoll", + "prctl", + "pread64", + "preadv", + "preadv2", + "prlimit64", + "pselect6", + "pwrite64", + "pwritev", + "pwritev2", + "read", + "readahead", + "readlink", + "readlinkat", + "readv", + "recv", + "recvfrom", + "recvmmsg", + "recvmsg", + "remap_file_pages", + "removexattr", + "rename", + "renameat", + "renameat2", + "restart_syscall", + "rmdir", + "rt_sigaction", + "rt_sigpending", + "rt_sigprocmask", + "rt_sigqueueinfo", + "rt_sigreturn", + "rt_sigsuspend", + "rt_sigtimedwait", + "rt_tgsigqueueinfo", + "sched_getaffinity", + "sched_getattr", + "sched_getparam", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_getscheduler", + "sched_rr_get_interval", + "sched_setaffinity", + "sched_setattr", + "sched_setparam", + "sched_setscheduler", + "sched_yield", + "seccomp", + "select", + "semctl", + "semget", + "semop", + "semtimedop", + "send", + "sendfile", + "sendfile64", + "sendmmsg", + "sendmsg", + "sendto", + "setfsgid", + "setfsgid32", + "setfsuid", + "setfsuid32", + "setgid", + "setgid32", + "setgroups", + "setgroups32", + "setitimer", + "setpgid", + "setpriority", + "setregid", + "setregid32", + "setresgid", + "setresgid32", + "setresuid", + "setresuid32", + "setreuid", + "setreuid32", + "setrlimit", + "set_robust_list", + "setsid", + "setsockopt", + "set_thread_area", + "set_tid_address", + "setuid", + "setuid32", + "setxattr", + "shmat", + "shmctl", + "shmdt", + "shmget", + "shutdown", + "sigaltstack", + "signalfd", + "signalfd4", + "sigreturn", + "socket", + "socketcall", + "socketpair", + "splice", + "stat", + "stat64", + "statfs", + "statfs64", + "statx", + "symlink", + "symlinkat", + "sync", + "sync_file_range", + "syncfs", + "sysinfo", + "tee", + "tgkill", + "time", + "timer_create", + "timer_delete", + "timerfd_create", + "timerfd_gettime", + "timerfd_settime", + "timer_getoverrun", + "timer_gettime", + "timer_settime", + "times", + "tkill", + "truncate", + "truncate64", + "ugetrlimit", + "umask", + "uname", + "unlink", + "unlinkat", + "utime", + "utimensat", + "utimes", + "vfork", + "vmsplice", + "wait4", + "waitid", + "waitpid", + "write", + "writev" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "ptrace" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 8, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 131072, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 131080, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 4294967295, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "arm_fadvise64_64", + "arm_sync_file_range", + "sync_file_range2", + "breakpoint", + "cacheflush", + "set_tls" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "arch_prctl" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "modify_ldt" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "clone" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "value": 2080505856, + "op": "SCMP_CMP_MASKED_EQ" + } + ] + }, + { + "names": [ + "chroot" + ], + "action": "SCMP_ACT_ALLOW" + } + ] + }, + "maskedPaths": [ + "/proc/acpi", + "/proc/config.gz", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/proc/signo", + "/proc/sig_catch", + "/proc/kbox", + "/proc/oom_extend", + "/proc/fdthreshold", + "/proc/fdstat", + "/proc/fdenable", + "/proc/files_panic_enable", + "/sys/firmware", + "/proc/cpuirqstat", + "/proc/memstat", + "/proc/iomem_ext", + "/proc/livepatch" + ], + "readonlyPaths": [ + "/proc/asound", + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger", + "/proc/sysrq-region-size" + ] + } +} diff --git a/test/specs/specs_extend/specs_extend_llt.cc b/test/specs/specs_extend/specs_extend_llt.cc new file mode 100644 index 0000000..cefee30 --- /dev/null +++ b/test/specs/specs_extend/specs_extend_llt.cc @@ -0,0 +1,288 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. + * iSulad licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * 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 v1 for more details. + * Description: specs extend llt + * Author: lifeng + * Create: 2020-02-18 + */ + +#include +#include +#include +#include "mock.h" +#include "oci_runtime_spec.h" +#include "specs.h" +#include "host_config.h" +#include "container_config.h" +#include "oci_llt_common.h" +#include +#include +#include "isulad_config_mock.h" +#include "oci_runtime_hooks.h" +#include "utils.h" +#include "specs_extend.h" + +using ::testing::Args; +using ::testing::ByRef; +using ::testing::SetArgPointee; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::NotNull; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::_; + +using namespace std; + +#define HOOKS_CONFIG_FILE "specs/specs_extend/hooks.json" + +TEST(make_sure_oci_spec_linux_llt, test_make_sure_oci_spec_linux) +{ + oci_runtime_spec *oci_spec = NULL; + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + ASSERT_EQ(make_sure_oci_spec_linux(oci_spec), 0); + ASSERT_TRUE(oci_spec->linux != NULL); + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(make_sure_oci_spec_process_llt, test_make_sure_oci_spec_process) +{ + oci_runtime_spec *oci_spec = NULL; + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + ASSERT_EQ(make_sure_oci_spec_process(oci_spec), 0); + ASSERT_TRUE(oci_spec->process != NULL); + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(make_sure_oci_spec_linux_resources_llt, test_make_sure_oci_spec_linux_resources) +{ + oci_runtime_spec *oci_spec = NULL; + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + ASSERT_EQ(make_sure_oci_spec_linux_resources(oci_spec), 0); + ASSERT_TRUE(oci_spec->linux != NULL); + ASSERT_TRUE(oci_spec->linux->resources != NULL); + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(make_sure_oci_spec_linux_resources_blkio_llt, test_make_sure_oci_spec_linux_resources_blkio) +{ + oci_runtime_spec *oci_spec = NULL; + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + ASSERT_EQ(make_sure_oci_spec_linux_resources_blkio(oci_spec), 0); + ASSERT_TRUE(oci_spec->linux != NULL); + ASSERT_TRUE(oci_spec->linux->resources != NULL); + ASSERT_TRUE(oci_spec->linux->resources->block_io != NULL); + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(merge_hooks_llt, test_merge_hooks_invalid) +{ + ASSERT_NE(merge_hooks(nullptr, nullptr), 0); +} + +TEST(merge_hooks_llt, test_merge_hooks_llt_2) +{ + oci_runtime_spec *oci_spec = NULL; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + oci_spec->hooks = (oci_runtime_spec_hooks*)util_common_calloc_s(sizeof(oci_runtime_spec_hooks)); + ASSERT_NE(merge_hooks(oci_spec->hooks, NULL), 0); + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(merge_hooks_llt, test_merge_hooks_llt_3) +{ + char *hooks_config_file = NULL; + oci_runtime_spec_hooks *hooks_spec = NULL; + char *err = NULL; + + hooks_config_file = json_path(HOOKS_CONFIG_FILE); + ASSERT_TRUE(hooks_config_file != NULL); + hooks_spec = oci_runtime_spec_hooks_parse_file(hooks_config_file, NULL, &err); + ASSERT_TRUE(hooks_spec != NULL); + free(err); + err = NULL; + free(hooks_config_file); + hooks_config_file = NULL; + ASSERT_NE(merge_hooks(NULL, hooks_spec), 0); + free_oci_runtime_spec_hooks(hooks_spec); + hooks_spec = NULL; +} + +TEST(merge_hooks_llt, test_merge_hooks_llt_4) +{ + char *hooks_config_file = NULL; + oci_runtime_spec_hooks *hooks_spec = NULL; + oci_runtime_spec *oci_spec = NULL; + char *err = NULL; + + // All parameter correct + hooks_config_file = json_path(HOOKS_CONFIG_FILE); + ASSERT_TRUE(hooks_config_file != NULL); + hooks_spec = oci_runtime_spec_hooks_parse_file(hooks_config_file, NULL, &err); + ASSERT_TRUE(hooks_spec != NULL); + free(err); + err = NULL; + free(hooks_config_file); + hooks_config_file = NULL; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + oci_spec->hooks = (oci_runtime_spec_hooks*)util_common_calloc_s(sizeof(oci_runtime_spec_hooks)); + + ASSERT_EQ(merge_hooks(oci_spec->hooks, hooks_spec), 0); + + free_oci_runtime_spec_hooks(hooks_spec); + hooks_spec = NULL; + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} +TEST(merge_hooks_llt, test_merge_hooks_llt_prestart) +{ + char *hooks_config_file = NULL; + oci_runtime_spec_hooks *hooks_spec = NULL; + oci_runtime_spec *oci_spec = NULL; + char *err = NULL; + + // All parameter correct + hooks_config_file = json_path(HOOKS_CONFIG_FILE); + ASSERT_TRUE(hooks_config_file != NULL); + hooks_spec = oci_runtime_spec_hooks_parse_file(hooks_config_file, NULL, &err); + ASSERT_TRUE(hooks_spec != NULL); + free(err); + err = NULL; + free(hooks_config_file); + hooks_config_file = NULL; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + oci_spec->hooks = (oci_runtime_spec_hooks*)util_common_calloc_s(sizeof(oci_runtime_spec_hooks)); + + ASSERT_EQ(merge_hooks(oci_spec->hooks, hooks_spec), 0); + ASSERT_EQ(oci_spec->hooks->prestart_len, 1); + ASSERT_STREQ(oci_spec->hooks->prestart[0]->path, "/home/hooks/start.bash"); + ASSERT_EQ(oci_spec->hooks->prestart[0]->args_len, 3); + ASSERT_STREQ(oci_spec->hooks->prestart[0]->args[0], "arg0"); + ASSERT_STREQ(oci_spec->hooks->prestart[0]->args[1], "arg1"); + ASSERT_STREQ(oci_spec->hooks->prestart[0]->args[2], "arg2"); + ASSERT_EQ(oci_spec->hooks->prestart[0]->env_len, 1); + ASSERT_STREQ(oci_spec->hooks->prestart[0]->env[0], "key1=value1"); + ASSERT_EQ(oci_spec->hooks->prestart[0]->timeout, 40); + + free_oci_runtime_spec_hooks(hooks_spec); + hooks_spec = NULL; + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(merge_hooks_llt, test_merge_hooks_llt_poststart) +{ + char *hooks_config_file = NULL; + oci_runtime_spec_hooks *hooks_spec = NULL; + oci_runtime_spec *oci_spec = NULL; + char *err = NULL; + + // All parameter correct + hooks_config_file = json_path(HOOKS_CONFIG_FILE); + ASSERT_TRUE(hooks_config_file != NULL); + hooks_spec = oci_runtime_spec_hooks_parse_file(hooks_config_file, NULL, &err); + ASSERT_TRUE(hooks_spec != NULL); + free(err); + err = NULL; + free(hooks_config_file); + hooks_config_file = NULL; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + oci_spec->hooks = (oci_runtime_spec_hooks*)util_common_calloc_s(sizeof(oci_runtime_spec_hooks)); + + ASSERT_EQ(merge_hooks(oci_spec->hooks, hooks_spec), 0); + ASSERT_EQ(oci_spec->hooks->poststart_len, 2); + ASSERT_STREQ(oci_spec->hooks->poststart[0]->path, "/home/hooks/post1.bash"); + ASSERT_EQ(oci_spec->hooks->poststart[0]->args_len, 3); + ASSERT_STREQ(oci_spec->hooks->poststart[0]->args[0], "arg5"); + ASSERT_STREQ(oci_spec->hooks->poststart[0]->args[1], "arg6"); + ASSERT_STREQ(oci_spec->hooks->poststart[0]->args[2], "arg7"); + ASSERT_EQ(oci_spec->hooks->poststart[0]->env_len, 1); + ASSERT_STREQ(oci_spec->hooks->poststart[0]->env[0], "key2=value221"); + ASSERT_EQ(oci_spec->hooks->poststart[0]->timeout, 60); + + ASSERT_STREQ(oci_spec->hooks->poststart[1]->path, "/home/hooks/post2.bash"); + ASSERT_EQ(oci_spec->hooks->poststart[1]->args_len, 3); + ASSERT_STREQ(oci_spec->hooks->poststart[1]->args[0], "arg51"); + ASSERT_STREQ(oci_spec->hooks->poststart[1]->args[1], "arg61"); + ASSERT_STREQ(oci_spec->hooks->poststart[1]->args[2], "arg71"); + ASSERT_EQ(oci_spec->hooks->poststart[1]->env_len, 1); + ASSERT_STREQ(oci_spec->hooks->poststart[1]->env[0], "key3=value3"); + ASSERT_EQ(oci_spec->hooks->poststart[1]->timeout, 61); + + free_oci_runtime_spec_hooks(hooks_spec); + hooks_spec = NULL; + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} + +TEST(merge_hooks_llt, test_merge_hooks_llt_poststop) +{ + char *hooks_config_file = NULL; + oci_runtime_spec_hooks *hooks_spec = NULL; + oci_runtime_spec *oci_spec = NULL; + char *err = NULL; + + // All parameter correct + hooks_config_file = json_path(HOOKS_CONFIG_FILE); + ASSERT_TRUE(hooks_config_file != NULL); + hooks_spec = oci_runtime_spec_hooks_parse_file(hooks_config_file, NULL, &err); + ASSERT_TRUE(hooks_spec != NULL); + free(err); + err = NULL; + free(hooks_config_file); + hooks_config_file = NULL; + + oci_spec = (oci_runtime_spec *) util_common_calloc_s(sizeof(oci_runtime_spec)); + ASSERT_TRUE(oci_spec != NULL); + oci_spec->hooks = (oci_runtime_spec_hooks*)util_common_calloc_s(sizeof(oci_runtime_spec_hooks)); + + ASSERT_EQ(merge_hooks(oci_spec->hooks, hooks_spec), 0); + ASSERT_EQ(oci_spec->hooks->poststop_len, 2); + ASSERT_STREQ(oci_spec->hooks->poststop[0]->path, "/home/hooks/stop1.bash"); + ASSERT_EQ(oci_spec->hooks->poststop[0]->args_len, 3); + ASSERT_STREQ(oci_spec->hooks->poststop[0]->args[0], "arg11"); + ASSERT_STREQ(oci_spec->hooks->poststop[0]->args[1], "arg12"); + ASSERT_STREQ(oci_spec->hooks->poststop[0]->args[2], "arg13"); + ASSERT_EQ(oci_spec->hooks->poststop[0]->env_len, 1); + ASSERT_STREQ(oci_spec->hooks->poststop[0]->env[0], "key2=value221"); + ASSERT_EQ(oci_spec->hooks->poststop[0]->timeout, 60); + + ASSERT_STREQ(oci_spec->hooks->poststop[1]->path, "/home/hooks/stop2.bash"); + ASSERT_EQ(oci_spec->hooks->poststop[1]->args_len, 3); + ASSERT_STREQ(oci_spec->hooks->poststop[1]->args[0], "arg52"); + ASSERT_STREQ(oci_spec->hooks->poststop[1]->args[1], "arg62"); + ASSERT_STREQ(oci_spec->hooks->poststop[1]->args[2], "arg72"); + ASSERT_EQ(oci_spec->hooks->poststop[1]->env_len, 1); + ASSERT_STREQ(oci_spec->hooks->poststop[1]->env[0], "key4=value4"); + ASSERT_EQ(oci_spec->hooks->poststop[1]->timeout, 62); + + free_oci_runtime_spec_hooks(hooks_spec); + hooks_spec = NULL; + free_oci_runtime_spec(oci_spec); + oci_spec = NULL; +} \ No newline at end of file