Package init

This commit is contained in:
overweight 2019-09-30 10:53:41 -04:00
commit 665cb60dbd
573 changed files with 116924 additions and 0 deletions

123
.clang-format Normal file
View File

@ -0,0 +1,123 @@
---
BasedOnStyle: llvm
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: false
# AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
# AllowAllConstructorInitializersOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
# AllowShortLambdasOnASingleLine: Empty
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
# AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | sort | uniq
ForEachMacros:
- 'linked_list_for_each_safe'
- 'linked_list_for_each'
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: Inner
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
# SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never
...

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
build
*.pyc

123
CMakeLists.txt Normal file
View File

@ -0,0 +1,123 @@
cmake_minimum_required (VERSION 3.12.1)
project (lcrd)
include(cmake/helper.cmake)
include(cmake/options.cmake)
include(cmake/set_build_flags.cmake)
#set(CMAKE_C_COMPILER "gcc" CACHE PATH "c compiler")
# Get the latest abbreviated commit hash of the working branch
execute_process(
COMMAND git rev-parse HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message("-- commit id: " ${GIT_COMMIT_HASH})
add_definitions(-DLCRD_GIT_COMMIT="${GIT_COMMIT_HASH}")
execute_process(
COMMAND sh -c "date --rfc-3339 ns | sed -e 's/ /T/'"
OUTPUT_VARIABLE BUILD_DATE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message("-- build time: " ${BUILD_DATE})
add_definitions(-DLCRD_BUILD_TIME="${BUILD_DATE}")
if (NOT LCRD_ROOT_PATH)
add_definitions(-DLCRD_ROOT_PATH="/var/lib/lcrd")
endif()
if (NOT LCRD_STATE_PATH)
add_definitions(-DLCRD_STATE_PATH="/var/run/lcrd")
endif()
if (LIB_INSTALL_DIR)
set(LIB_INSTALL_DIR_DEFAULT ${LIB_INSTALL_DIR})
else()
set(LIB_INSTALL_DIR_DEFAULT "lib")
endif()
# check depends library and headers
include(cmake/checker.cmake)
if (CHECKER_RESULT)
message(FATAL_ERROR "ERROR: Check library and headers failed")
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
"${CMAKE_BINARY_DIR}/conf/config.h"
)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/lcrd.pc.in"
"${CMAKE_BINARY_DIR}/conf/lcrd.pc"
)
if (GRPC_CONNECTOR)
# parse .proto files
include(cmake/protoc.cmake)
endif()
# enable embedded image
if (ENABLE_EMBEDDED)
add_definitions(-DENABLE_EMBEDDED_IMAGE=1)
endif()
# disable oci image
if (NOT DISABLE_OCI)
add_definitions(-DENABLE_OCI_IMAGE=1)
endif()
# llt and coverage
SET(CMAKE_VERBOSE_MAKEFILE OFF)
OPTION(ENABLE_COVERAGE "coverage switch" OFF)
IF(ENABLE_COVERAGE)
MESSAGE(STATUS "Enable coverage compile option")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage")
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage -lgcov")
ENDIF(ENABLE_COVERAGE)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src)
OPTION(ENABLE_LLT "llt switch" OFF)
IF(ENABLE_LLT)
enable_testing()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test)
ENDIF(ENABLE_LLT)
# install all files
install(FILES ${CMAKE_BINARY_DIR}/conf/lcrd.pc
DESTINATION ${LIB_INSTALL_DIR_DEFAULT}/pkgconfig PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE)
install(FILES src/liblcrc.h
DESTINATION include/lcrd)
install(FILES src/connect/client/lcrc_connect.h
DESTINATION include/lcrd)
install(FILES src/container_def.h
DESTINATION include/lcrd)
install(FILES src/types_def.h
DESTINATION include/lcrd)
install(FILES src/error.h
DESTINATION include/lcrd)
install(FILES src/engines/engine.h
DESTINATION include/lcrd)
# install config files
set(conf_prefix "/etc")
if (CMAKE_INSTALL_SYSCONFDIR)
set(conf_prefix ${CMAKE_INSTALL_SYSCONFDIR})
endif()
install(FILES src/contrib/config/daemon.json
DESTINATION ${conf_prefix}/isulad PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE)
install(FILES src/contrib/config/config.json
DESTINATION ${conf_prefix}/default/lcrd PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE)
install(FILES src/contrib/config/seccomp_default.json
DESTINATION ${conf_prefix}/isulad PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE)
install(FILES src/contrib/config/hooks/default.json
DESTINATION ${conf_prefix}/default/lcrd/hooks PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE)
install(FILES src/contrib/sysmonitor/isulad-check.sh
DESTINATION ${conf_prefix}/default/lcrd PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
install(FILES src/contrib/sysmonitor/isulad-monit
DESTINATION ${conf_prefix}/sysmonitor/process PERMISSIONS OWNER_READ OWNER_WRITE)

121
License/LICENSE Normal file
View File

@ -0,0 +1,121 @@
木兰宽松许可证, 第1版
木兰宽松许可证, 第1版
2019年8月 http://license.coscl.org.cn/MulanPSL
您对“软件”的复制、使用、修改及分发受木兰宽松许可证第1版“本许可证”的如下条款的约束
0. 定义
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
“法人实体”是指提交贡献的机构及其“关联实体”。
“关联实体”是指对“本许可证”下的一方而言控制、受控制或与其共同受控制的机构此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
1. 授予版权许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
2. 授予专利许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括仅因您或他人修改“贡献”或其他结合而将必然会侵犯到的专利权利要求。如您或您的“关联实体”直接或间接地(包括通过代理、专利被许可人或受让人),就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
3. 无商标许可
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可但您为满足第4条规定的声明义务而必须使用除外。
4. 分发限制
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
5. 免责声明与责任限制
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
条款结束。
如何将木兰宽松许可证第1版应用到您的软件
如果您希望将木兰宽松许可证第1版应用到您的新软件为了方便接收者查阅建议您完成如下三步
1 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
2 请您在软件包的一级目录下创建以“LICENSE”为名的文件将整个许可证文本放入该文件中
3 请将如下声明文本放入每个源文件的头部注释中。
Copyright (c) [2019] [name of copyright holder]
[Software Name] is 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.
Mulan Permissive Software LicenseVersion 1
Mulan Permissive Software LicenseVersion 1 (Mulan PSL v1)
August 2019 http://license.coscl.org.cn/MulanPSL
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v1 (this License) with following terms and conditions:
0. Definition
Software means the program and related documents which are comprised of those Contribution and licensed under this License.
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
Legal Entity means the entity making a Contribution and all its Affiliates.
Affiliates means entities that control, or are controlled by, or are under common control with a party to this License, control means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
Contribution means the copyrightable work licensed by a particular Contributor under this License.
1. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
2. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed, excluding of any patent claims solely be infringed by your or others modification or other combinations. If you or your Affiliates directly or indirectly (including through an agent, patent licensee or assignee, institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
3. No Trademark License
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4.
4. Distribution Restriction
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
5. Disclaimer of Warranty and Limitation of Liability
The Software and Contribution in it are provided without warranties of any kind, either express or implied. In no event shall any Contributor or copyright holder be liable to you for any damages, including, but not limited to any direct, or indirect, special or consequential damages arising from your use or inability to use the Software or the Contribution in it, no matter how its caused or based on which legal theory, even if advised of the possibility of such damages.
End of the Terms and Conditions
How to apply the Mulan Permissive Software LicenseVersion 1 (Mulan PSL v1) to your software
To apply the Mulan PSL v1 to your work, for easy identification by recipients, you are suggested to complete following three steps:
i. Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
ii. Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
iii. Attach the statement to the appropriate annotated syntax at the beginning of each source file.
Copyright (c) [2019] [name of copyright holder]
[Software Name] is 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.

25
README.md Normal file
View File

@ -0,0 +1,25 @@
# iSulad
This is a umbrella project for gRPC-services based Lightweight Container Runtime Daemon.
iSulad provide a unified architecture to meet the different needs of CT and IT.
Compared with Docker written by Golang, iSulad has the characteristics of light, agile, fast,
not limited by hardware specifications and architecture, and can be applied more widely.
## How to Contribute
We always welcome new contributors. And we are happy to provide guidance for the new contributors.
iSulad follows the kernel coding conventions. You can find a detailed introduction at:
- https://www.kernel.org/doc/html/v4.10/process/coding-style.html
## Building
Without considering distribution specific details a simple
mkdir -p build && cd ./build && cmake .. && make && sudo make install
is usually sufficient.
## Licensing
iSulad is licensed under the Mulan PSL v1.

147
cmake/checker.cmake Normal file
View File

@ -0,0 +1,147 @@
include(CheckIncludeFile)
# check depends library and headers
find_package(PkgConfig REQUIRED)
# check python
find_program(CMD_PYTHON python)
_CHECK(CMD_PYTHON "CMD_PYTHON-NOTFOUND" "python")
# check tools
find_program(CMD_TAR tar)
_CHECK(CMD_TAR "CMD_TAR-NOTFOUND" "tar")
find_program(CMD_SHA256 sha256sum)
_CHECK(CMD_SHA256 "CMD_SHA256-NOTFOUND" "sha256sum")
find_program(CMD_GZIP gzip)
_CHECK(CMD_GZIP "CMD_GZIP-NOTFOUND" "gzip")
# check std headers ctype.h sys/param.h sys/capability.h
find_path(STD_HEADER_CTYPE ctype.h)
_CHECK(STD_HEADER_CTYPE "STD_HEADER_CTYPE-NOTFOUND" "ctype.h")
find_path(STD_HEADER_SYS_PARAM sys/param.h)
_CHECK(STD_HEADER_SYS_PARAM "STD_HEADER_SYS_PARAM-NOTFOUND" "sys/param.h")
CHECK_INCLUDE_FILE(sys/capability.h HAVE_LIBCAP)
if (HAVE_LIBCAP)
message("-- found linux capability.h --- works")
add_definitions(-DHAVE_LIBCAP_H=1)
else()
message("-- found linux capability.h --- no")
endif()
if (SYSTEMD_NOTIFY)
# check systemd
find_path(SYSTEMD_INCLUDE_DIR systemd/sd-daemon.h)
_CHECK(SYSTEMD_INCLUDE_DIR "SYSTEMD_INCLUDE_DIR-NOTFOUND" "systemd/sd-daemon.h")
find_library(SYSTEMD_LIBRARY systemd)
_CHECK(SYSTEMD_LIBRARY "SYSTEMD_LIBRARY-NOTFOUND" "libsystemd.so")
endif()
# check zlib
pkg_check_modules(PC_ZLIB "zlib>=1.2.8")
find_path(ZLIB_INCLUDE_DIR zlib.h
HINTS ${PC_ZLIB_INCLUDEDIR} ${PC_ZLIB_INCLUDE_DIRS})
_CHECK(ZLIB_INCLUDE_DIR "ZLIB_INCLUDE_DIR-NOTFOUND" "zlib.h")
find_library(ZLIB_LIBRARY z
HINTS ${PC_ZLIB_LIBDIR} ${PC_ZLIB_LIBRARY_DIRS})
_CHECK(ZLIB_LIBRARY "ZLIB_LIBRARY-NOTFOUND" "libz.so")
# check securec
find_path(LIBSECUREC_INCLUDE_DIR securec.h)
_CHECK(LIBSECUREC_INCLUDE_DIR "LIBSECUREC_INCLUDE_DIR-NOTFOUND" "securec.h")
find_library(LIBSECUREC_LIBRARY securec)
_CHECK(LIBSECUREC_LIBRARY "LIBSECUREC_LIBRARY-NOTFOUND" "libsecurec.so")
# check libyajl
pkg_check_modules(PC_LIBYAJL REQUIRED "yajl>=2")
find_path(LIBYAJL_INCLUDE_DIR yajl/yajl_tree.h
HINTS ${PC_LIBYAJL_INCLUDEDIR} ${PC_LIBYAJL_INCLUDE_DIRS})
_CHECK(LIBYAJL_INCLUDE_DIR "LIBYAJL_INCLUDE_DIR-NOTFOUND" "yajl/yajl_tree.h")
find_library(LIBYAJL_LIBRARY yajl
HINTS ${PC_LIBYAJL_LIBDIR} ${PC_LIBYAJL_LIBRARY_DIRS})
_CHECK(LIBYAJL_LIBRARY "LIBYAJL_LIBRARY-NOTFOUND" "libyajl.so")
find_path(HTTP_PARSER_INCLUDE_DIR http_parser.h)
_CHECK(HTTP_PARSER_INCLUDE_DIR "HTTP_PARSER_INCLUDE_DIR-NOTFOUND" "http_parser.h")
find_library(HTTP_PARSER_LIBRARY http_parser)
_CHECK(HTTP_PARSER_LIBRARY "HTTP_PARSER_LIBRARY-NOTFOUND" "libhttp_parser.so")
pkg_check_modules(PC_CURL "libcurl>=7.4.0")
find_path(CURL_INCLUDE_DIR "curl/curl.h"
HINTS ${PC_CURL_INCLUDEDIR} ${PC_CURL_INCLUDE_DIRS})
_CHECK(CURL_INCLUDE_DIR "CURL_INCLUDE_DIR-NOTFOUND" "curl/curl.h")
find_library(CURL_LIBRARY curl
HINTS ${PC_CURL_LIBDIR} ${PC_CURL_LIBRARY_DIRS})
_CHECK(CURL_LIBRARY "CURL_LIBRARY-NOTFOUND" "libcurl.so")
if (OPENSSL_VERIFY)
find_path(OPENSSL_INCLUDE_DIR openssl/x509.h)
_CHECK(OPENSSL_INCLUDE_DIR "OPENSSL_INCLUDE_DIR-NOTFOUND" "openssl/x509.h")
endif()
if (GRPC_CONNECTOR)
# check websocket
find_path(WEBSOCKET_INCLUDE_DIR libwebsockets.h)
_CHECK(WEBSOCKET_INCLUDE_DIR "WEBSOCKET_INCLUDE_DIR-NOTFOUND" libwebsockets.h)
find_library(WEBSOCKET_LIBRARY websockets)
_CHECK(WEBSOCKET_LIBRARY "WEBSOCKET_LIBRARY-NOTFOUND" "libwebsockets.so")
# check protobuf
pkg_check_modules(PC_PROTOBUF "protobuf>=3.1.0")
find_library(PROTOBUF_LIBRARY protobuf
HINTS ${PC_PROTOBUF_LIBDIR} ${PC_PROTOBUF_LIBRARY_DIRS})
_CHECK(PROTOBUF_LIBRARY "PROTOBUF_LIBRARY-NOTFOUND" "libprotobuf.so")
find_program(CMD_PROTOC protoc)
_CHECK(CMD_PROTOC "CMD_PROTOC-NOTFOUND" "protoc")
find_program(CMD_GRPC_CPP_PLUGIN grpc_cpp_plugin)
_CHECK(CMD_GRPC_CPP_PLUGIN "CMD_GRPC_CPP_PLUGIN-NOTFOUND" "grpc_cpp_plugin")
# check grpc
find_path(GRPC_INCLUDE_DIR grpc/grpc.h)
_CHECK(GRPC_INCLUDE_DIR "GRPC_INCLUDE_DIR-NOTFOUND" "grpc/grpc.h")
find_library(GRPC_PP_REFLECTION_LIBRARY grpc++_reflection)
_CHECK(GRPC_PP_REFLECTION_LIBRARY "GRPC_PP_REFLECTION_LIBRARY-NOTFOUND" "libgrpc++_reflection.so")
find_library(GRPC_PP_LIBRARY grpc++)
_CHECK(GRPC_PP_LIBRARY "GRPC_PP_LIBRARY-NOTFOUND" "libgrpc++.so")
find_library(GRPC_LIBRARY grpc)
_CHECK(GRPC_LIBRARY "GRPC_LIBRARY-NOTFOUND" "libgrpc.so")
find_library(GPR_LIBRARY gpr)
_CHECK(GPR_LIBRARY "GPR_LIBRARY-NOTFOUND" "libgpr.so")
# check clibcni
pkg_check_modules(PC_CLIBCNI REQUIRED "clibcni")
find_path(CLIBCNI_INCLUDE_DIR clibcni/api.h
HINTS ${PC_CLIBCNI_INCLUDEDIR} ${PC_CLIBCNI_INCLUDE_DIRS})
_CHECK(CLIBCNI_INCLUDE_DIR "CLIBCNI_INCLUDE_DIR-NOTFOUND" "clibcni/api.h")
find_library(CLIBCNI_LIBRARY clibcni
HINTS ${PC_CLIBCNI_LIBDIR} ${PC_CLIBCNI_LIBRARY_DIRS})
_CHECK(CLIBCNI_LIBRARY "CLIBCNI_LIBRARY-NOTFOUND" "libclibcni.so")
else()
pkg_check_modules(PC_EVENT "event>=2.1.8")
find_path(EVENT_INCLUDE_DIR event.h
HINTS ${PC_EVENT_INCLUDEDIR} ${PC_EVENT_INCLUDE_DIRS})
_CHECK(EVENT_INCLUDE_DIR "EVENT_INCLUDE_DIR-NOTFOUND" "event.h")
find_library(EVENT_LIBRARY event
HINTS ${PC_EVENT_LIBDIR} ${PC_EVENT_LIBRARY_DIRS})
_CHECK(EVENT_LIBRARY "EVENT_LIBRARY-NOTFOUND" "libevent.so")
pkg_check_modules(PC_EVHTP "evhtp>=1.2.16")
find_path(EVHTP_INCLUDE_DIR evhtp/evhtp.h
HINTS ${PC_EVHTP_INCLUDEDIR} ${PC_EVHTP_INCLUDE_DIRS})
_CHECK(EVHTP_INCLUDE_DIR "EVHTP_INCLUDE_DIR-NOTFOUND" "evhtp/evhtp.h")
find_library(EVHTP_LIBRARY evhtp
HINTS ${PC_EVHTP_LIBDIR} ${PC_EVHTP_LIBRARY_DIRS})
_CHECK(EVHTP_LIBRARY "EVHTP_LIBRARY-NOTFOUND" "libevhtp.so")
endif()
if (ENABLE_EMBEDDED)
pkg_check_modules(PC_SQLITE3 "sqlite3>=3.7.17")
find_path(SQLIT3_INCLUDE_DIR sqlite3.h
HINTS ${PC_SQLITE3_INCLUDEDIR} ${PC_SQLITE3_INCLUDE_DIRS})
_CHECK(SQLIT3_INCLUDE_DIR "SQLIT3_INCLUDE_DIR-NOTFOUND" "sqlite3.h")
find_library(SQLITE3_LIBRARY sqlite3
HINTS ${PC_SQLITE3_LIBDIR} ${PC_SQLITE3_LIBRARY_DIRS})
_CHECK(SQLITE3_LIBRARY "SQLITE3_LIBRARY-NOTFOUND" "libsqlite3.so")
endif()

9
cmake/helper.cmake Normal file
View File

@ -0,0 +1,9 @@
# use to check result
macro(_CHECK)
if (${ARGV0} STREQUAL "${ARGV1}")
message("ERROR: can not find " ${ARGV2} " program")
set(CHECKER_RESULT 1)
else()
message("-- found " ${ARGV2} " --- works")
endif()
endmacro()

47
cmake/options.cmake Normal file
View File

@ -0,0 +1,47 @@
# build which type of lcr library
option(USESHARED "set type of libs, default is shared" ON)
if (USESHARED STREQUAL "ON")
set(LIBTYPE "SHARED")
message("-- Build shared library")
else ()
set(LIBTYPE "STATIC")
message("-- Build static library")
endif()
option(ENABLE_GRPC "use grpc as connector" ON)
if (ENABLE_GRPC STREQUAL "ON")
add_definitions(-DGRPC_CONNECTOR)
set(GRPC_CONNECTOR 1)
endif()
option(ENABLE_SYSTEMD_NOTIFY "enable systemd notify" ON)
if (ENABLE_SYSTEMD_NOTIFY STREQUAL "ON")
add_definitions(-DSYSTEMD_NOTIFY)
set(SYSTEMD_NOTIFY 1)
endif()
option(ENABLE_OPENSSL_VERIFY "use ssl with connector" ON)
if (ENABLE_OPENSSL_VERIFY STREQUAL "ON")
add_definitions(-DOPENSSL_VERIFY)
set(OPENSSL_VERIFY 1)
endif()
option(PACKAGE "set lcrd package" ON)
if (PACKAGE STREQUAL "ON")
set(LCRD_PACKAGE "iSulad")
endif()
option(VERSION "set lcrd version" ON)
if (VERSION STREQUAL "ON")
set(LCRD_VERSION "1.0.31")
endif()
option(DEBUG "set lcrd gcc option" ON)
if (DEBUG STREQUAL "ON")
add_definitions("-g -O2")
endif()
option(GCOV "set lcrd gcov option" OFF)
if (GCOV STREQUAL "ON")
set(ISULAD_GCOV "ON")
endif()

62
cmake/protoc.cmake Normal file
View File

@ -0,0 +1,62 @@
set(PROTOS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/api/services)
set(TYPES_PROTOS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/api/types)
set(GRPC_OUT_PRE_PATH ${CMAKE_BINARY_DIR}/grpc)
set(TYPES_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/types)
set(CONTAINER_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/containers)
set(IMAGE_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/images)
set(CRI_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/cri)
execute_process(COMMAND mkdir -p ${TYPES_PROTOS_OUT_PATH})
execute_process(COMMAND mkdir -p ${CONTAINER_PROTOS_OUT_PATH})
execute_process(COMMAND mkdir -p ${IMAGE_PROTOS_OUT_PATH})
execute_process(COMMAND mkdir -p ${CRI_PROTOS_OUT_PATH})
execute_process(COMMAND ${CMD_PROTOC} -I ${TYPES_PROTOS_PATH} --cpp_out=${TYPES_PROTOS_OUT_PATH}
${TYPES_PROTOS_PATH}/descriptor.proto ERROR_VARIABLE types_err)
if (types_err)
message("Parse types.proto failed: ")
message(FATAL_ERROR ${types_err})
endif()
execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/containers --cpp_out=${CONTAINER_PROTOS_OUT_PATH}
${PROTOS_PATH}/containers/container.proto ERROR_VARIABLE containers_err)
if (containers_err)
message("Parse containers.proto failed: ")
message(FATAL_ERROR ${containers_err})
endif()
execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/containers --grpc_out=${CONTAINER_PROTOS_OUT_PATH}
--plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/containers/container.proto ERROR_VARIABLE containers_err)
if (containers_err)
message("Parse containers.proto plugin failed: ")
message(FATAL_ERROR ${containers_err})
endif()
execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images -I ${TYPES_PROTOS_PATH}
--cpp_out=${IMAGE_PROTOS_OUT_PATH} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err)
if (images_err)
message("Parse images.proto failed: ")
message(FATAL_ERROR ${images_err})
endif()
execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images -I ${TYPES_PROTOS_PATH} --grpc_out=${IMAGE_PROTOS_OUT_PATH}
--plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err)
if (images_err)
message("Parse images.proto plugin failed: ")
message(FATAL_ERROR ${images_err})
endif()
execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/cri --cpp_out=${CRI_PROTOS_OUT_PATH} ${PROTOS_PATH}/cri/api.proto
ERROR_VARIABLE cri_err)
if (cri_err)
message("Parse cri.proto failed: ")
message(FATAL_ERROR ${cri_err})
endif()
execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/cri --grpc_out=${CRI_PROTOS_OUT_PATH}
--plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/cri/api.proto ERROR_VARIABLE cri_err)
if (cri_err)
message("Parse cri.proto plugin failed: ")
message(FATAL_ERROR ${cri_err})
endif()

View File

@ -0,0 +1,16 @@
# set common FLAGS
set(CMAKE_C_FLAGS "-fPIC -fstack-protector-all -D_FORTIFY_SOURCE=2 -O2 -Wall -Werror -rdynamic")
if (GRPC_CONNECTOR)
set(CMAKE_CXX_FLAGS "-fPIC -std=c++11 -fstack-protector-all -D_FORTIFY_SOURCE=2 -O2 -Wall -Werror")
endif()
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-E -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wtrampolines -fPIE -pie -shared -pthread")
set(CMAKE_EXE_LINKER_FLAGS "-Wl,-E -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wtrampolines -fPIE -pie")
if (ISULAD_GCOV)
set(CMAKE_C_FLAGS_DEBUG "-Wall -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -fprofile-arcs -ftest-coverage")
message("-----CXXFLAGS: " ${CMAKE_CXX_FLAGS_DEBUG})
message("------compile with gcov-------------")
message("-----CFLAGS: " ${CMAKE_C_FLAGS_DEBUG})
message("------------------------------------")
endif()

1
config.h.in Normal file
View File

@ -0,0 +1 @@
#cmakedefine VERSION "@LCRD_VERSION@"

41
docs/architecture.md Normal file
View File

@ -0,0 +1,41 @@
# iSulad Architecture
## Overview
![architecture](design/architecture.png)
iSulad是一个符合OCI标准的容器运行引擎强调简单性、健壮性和轻量化。它作为守护进程提供服务可以管理其主机系统的整个容器生命周期镜像的传输和存储、容器执行和监控管理、容器资源管理以及网络等。iSulad对外提供与docker类似的CLI人机接口可以使用与docker类似的命令进行容器管理并且提供符合CRI接口标准的gRPC API可供kubernetes\Hasen 按照CRI接口协议调用。
为了方便理解我们将iSulad的行为单元分成不同的模块模块大致被组织成子系统。了解这些模块、子系统及其关系是修改和扩展iSulad的关键
本文档将仅描述各个模块的high-level功能设计。有关每个模块的详细信息请参阅相关设计文档。
## 子系统
外部用户通过调用子系统提供的GRPC API与iSulad进行交互。
- **image service** : 镜像管理服务,提供镜像相关操作,如镜像下载、查询、删除等
- **execution service**: 容器生命周期管理服务,提供容器的相关操作,如容器创建、启动、删除等
- **network**网络子模块负责CRI的Pod的网络管理能力。当Pod启动时通过CNI的接口把该Pod加入到配置文件制定的网络平面中当Pod停止时通过CNI的接口把该Pod从所在的网络平面中退出并且清理相关的网络资源。
## 模块
- **image content** : 管理镜像元数据以及容器文件系统。
- **resource manage**: 容器资源管理如设置可用cpu、memory等资源限制
- **Executor**执行实际容器操作的runtime提供lcr作为默认runtime可通过plugin机制扩展
- **Events**:容器事件收集
- **Plugins**:提供插件机制,通过不同插件,实现扩展容器功能。
- **DFX**提供日志机制用于定位问题提供garbage collect 机制回收容器D/Z 等异常容器资源具备DFX能力。
### 网络架构设计
架构图,如下:
![CNI_architecture](./design/CNI_architecture.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

81
docs/developer_guide.md Normal file
View File

@ -0,0 +1,81 @@
# 警告
本文档专为开发人员编写:不适用于最终用户。
# 假设
- 您正工作在一台正常运转的测试或开发机器上。
# 创建开发环境
您可以使用下面两种方式创建开发环境。
## 在主机上安装iSulad
推荐的方式是在您的主机上[安装iSulad的依赖组件](http://code.huawei.com/containers/iSulad/blob/cri/documentation/install_guide.md)安装手册将指导您安装所有iSulad必须的组件包括protobuf、gRPC、lxc、lcr、iSulad等。
## 在容器中安装iSulad
### 依赖
在主机上安装docker。
下载[crictl-1.0.0-alpha.1](https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.0.0-alpha.1/crictl-1.0.0-alpha.1-linux-amd64.tar.gz)并放置于`/root/golang`路径下。
```sh
$ ls /root/golang/
crictl-1.0.0-alpha.1-linux-amd64.tar.gz
```
您可能还需要配置insecure-registry以下载dockerhub的镜像。
- 对于centos` /etc/sysconfig/docker`文件中添加`OPTIONS='--insecure-registry rnd-dockerhub.huawei.com'`
- 对于ubuntu` /etc/docker/daemon.json`中添加`{\"insecure-registries\":[\"rnd-dockerhub.huawei.com\"]}`
### 安装
```sh
$ ./CI/prepare_compile_env.sh
```
脚本执行完后,将运行一个名为`isulad-compile-env-$commit`的容器,您可以执行`docker exec -it isulad-compile-env-$commit /bin/bash`命令进入该容器iSulad的源码在容器内的根目录`/isulad`下。
# 编码风格
首先您应该安装[Artistic Style](http://astyle.sourceforge.net)。
## 检查代码风格
修改完代码后,通过以下命令查看是否存在代码风格问题。
```sh
$ ./tools/check-syntax
```
## 修复代码风格
修改完代码后,通过以下命令尝试修复代码风格问题。
```sh
$ ./tools/check-syntax -f
```
# 修改Proto文件
如果涉及gRPC接口变更需修改`./src/api/services/`下的[Proto](https://developers.google.com/protocol-buffers/docs/proto3)文件。修改完成后,重新[编译iSulad](http://code.huawei.com/containers/iSulad/blob/cri/documentation/install_guide.md#build-lcrd)。
# 添加json-schema文件
当您需要解析新的json文件时要在`src/json/schema/schema`路径下添加[json-schema](http://json-schema.org)文件,具体要求参考[iSula_C-json反射脚本使用说明](http://code.huawei.com/iSula/MayTheForceBeWithYou/blob/master/isulad/iSula%20C-Json%E5%8F%8D%E5%B0%84%E8%84%9A%E6%9C%AC%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E.docx)。
# 如何写commit message
如果提交了测试脚本的MR需要在iSulad的commit信息中添加测试脚本MR的信息。在commit信息的reason后面添加一行command: "测试脚本MR的路径和分支"。示例如下:
```sh
isulad: xxxxx
DTS/AR: XXXX
reason: xxxxx
command: "git fetch http://code-sh.rnd.huawei.com/xxxxxxxxx/isula_testcases.git console"
```

241
docs/install_guide.md Normal file
View File

@ -0,0 +1,241 @@
## Dependencies
This project depends on gRPC (need protobuf at least v3.1.0, gRPC at least v1.1.0) or REST (need libevent 2.1.8, libcurl at least 7.40, http-parser at least 2.6.2, local modified libevhtp), LCR. Other version are not tested, nor supported.
## Installation steps:
### Initialization
```sh
$ # for ubuntu
$ sudo apt-get install unzip libtool automake autoconf g++ cmake curl zlib1g-dev libcap-dev libseccomp-dev libyajl-dev libsqlite3-dev libwebsockets-dev
$ # for centos/RTOS
$ sudo yum install gcc-c++ autoconf libtool unzip automake cmake curl zlib-devel libcap-devel libseccomp-devel yajl-devel sqlite-devel libwebsockets-devel
```
### protobuf v3.5.0
Compile protobuf from source code:
```sh
$ git clone http://dgggit09-rd.huawei.com/a/euleros/third_party/open_source/userspace/protobuf
$ cd protobuf
$ git checkout -b next origin/next
$ tar -xf protobuf-3.5.0.tar.gz
$ cp googlemock-1.7.0.tar.gz googletest-1.7.0.tar.gz 0001-fix-build-on-s390x.patch protobuf-3.5.0
$ cd protobuf-3.5.0
$ tar -xf googlemock-1.7.0.tar.gz
$ tar -xf googletest-1.7.0.tar.gz
$ mv googlemock-release-1.7.0 gmock
$ tar -xf googletest-1.7.0.tar.gz -C gmock
$ mv gmock/googletest-release-1.7.0 gmock/gtest
$ patch -p1 < 0001-fix-build-on-s390x.patch
$ ./autogen.sh # Because of internal network issue, we need to change curl to allow insecure connections (curl -k)
$ ./configure
$ make -j
$ sudo make install
$ sudo ldconfig
```
### gRPC v1.17.1
Compile the gRPC C Core library
```sh
$ git clone http://dgggit09-rd.huawei.com/a/euleros/third_party/open_source/userspace/grpc
$ cd grpc
$ tar xf grpc-1.17.1.tar.gz
$ cd grpc-1.17.1
$ git checkout -b next origin/next
$ patch -p1 < ../0001-Do-not-build-the-Ruby-plugin.patch
$ patch -p1 < ../0001-enforce-system-crypto-policies.patch
$ patch -p1 < ../0002-patch-from-15532.patch
$ patch -p1 < ../cxx-Arg-List-Too-Long.patch
$ make -j
$ sudo make install
$ sudo ldconfig
```
### clibcni
Compile clibcni from source code:
```sh
$ git clone http://dgggit09-rd.huawei.com/a/euleros/self_src/userspace/clibcni
$ cd clibcni
$ git checkout -b next_docker origin/next_docker
$ rm -rf build
$ mkdir build && cd build
$ cmake ..
$ make -j
$ sudo make install
$ sudo ldconfig
```
if enbale testcase
```sh
$ rm -rf build
$ mkdir build && cd build
$ cmake -DENABLE_TESTS=ON ..
$ make -j
$ sudo make install
$ sudo ldconfig
$ cd tests && ./cni_test
$ cd -
```
### containernetworking plugins
Compile containernetworking plugins from source code:
```sh
$ git clone http://code-sh.rnd.huawei.com/containers/plugins/plugins.git
$ cd plugins
$ git checkout critest
$ ./build.sh
$ mkdir -p /opt/cni/bin
$ cp bin/* /opt/cni/bin/
```
### iSulad-kit
Compile iSulad-kit from source code:
```sh
$ git clone http://dgggit09-rd.huawei.com/a/euleros/self_src/userspace/iSulad-kit
$ git clone http://dgggit09-rd.huawei.com/a/euleros/third_party/open_source/userspace/skopeo
$ cd skopeo
$ git checkout -b next_docker origin/next_docker
$ mkdir ./tmp
$ tar -zxf skopeo-e814f96.tar.gz --strip-components 1 -C ./tmp
$ cp -r ./tmp/vendor ../iSulad-kit/
$ cd ../iSulad-kit
$ git checkout -b next_docker origin/next_docker
$ patch -p1 -F1 -s < ../skopeo/backport-update-vendor-to-e96a9b0e1b9019f9.patch
# apply the patchs
$ cp ./patch/* ./
$ cat series-patch.conf | while read line
do
if [[ $line == '' || $line =~ ^\s*# ]]; then
continue
fi
patch -p1 -F1 -s < $line
done
$ make -j
$ make install
```
### LXC
Compile lxc from source code:
```sh
$ git clone http://dgggit09-rd.huawei.com/a/euleros/third_party/open_source/userspace/lxc
$ cd lxc
$ git checkout -b next_docker origin/next_docker
$ tar xf lxc-3.0.3.tar.gz
$ cd lxc-3.0.3
$ mv ../*.patch .
# official patch
$ for var in $(ls lxc-*.patch | sort -n)
do
if [[ "$var" =~ "CVE-2019-5736" ]]; then
echo "ignoring CVE patch cause valgrind can not work"
continue
fi
patch -p1 < ${var}
done
# self-developing patch
$ for var in $(ls huawei-*.patch | sort -n)
do
patch -p1 < ${var}
done
$ ./autogen.sh
$ ./configure
$ make -j (If the GCC version on the system is greater than 7, please add CFLAGS="-Wno-error" option)
$ sudo make install
$ sudo ldconfig
```
### huawei securec library
Compile huawei securec library from source code:
```sh
$ git clone git@code-sh.huawei.com:containers/securec.git
$ cd securec
$ ./autogen.sh
$ ./configue
$ make -j $(nproc)
$ sudo make install
$ sudo ldconfig
```
### LCR
Note: If you encounter an error like "You must install [project] >= [version]" during executing "./configure",
please export the environment variable
```sh
$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
```
Compile lcr from source code:
```sh
$ git clone http://dgggit09-rd.huawei.com/a/euleros/self_src/userspace/lcr
$ cd lcr
$ git checkout -b next_docker origin/next_docker
$ mkdir -p build
$ cd build
$ cmake ../
$ make -j
$ sudo make install
$ sudo ldconfig
```
## Build LCRD
Note: If you encounter an error like "not found libcurl" during executing "./configure" on the ubuntu system,
please execute the following command:
```sh
$ sudo apt-get install libcurl4-gnutls-dev
```
In most cases, if we do not need to change the interface API(container.proto), just build the server and client like this:
```sh
$ git clone http://dgggit09-rd.huawei.com/a/euleros/self_src/userspace/iSulad
$ cd iSulad
$ git checkout -b next_docker origin/next_docker
$ rm -rf build
$ mkdir build && cd build
# To enable gRPC, configure lcrd by default
$ cmake ../
$ make -j (If the GCC version on the system is greater than 7, please add CFLAGS="-Wno-error" option)
$ sudo make install
$ sudo ldconfig
```
## Run
### Start daemon
Note: if you encounter an error like "error while loading shared libraries" when start the daemon ,
please execute the following command:
```sh
$ sudo echo "/usr/local/lib" >> /etc/ld.so.conf
```
You should have built and installed lcrd and lcrc. To run the daemon:
```sh
$ sudo lcrd # run the lcrd server with default socket name and default log level and images manage function
```
### Download rootfs
To create a container, you should have downloaded rootfs to your platform like this:
```sh
$ mkdir $HOME/myrootfs
$ sudo lcr-pull --name ubuntu --rootfs $HOME/myrootfs --dist ubuntu -r xenial -a amd64
```
If lcrd started with the images manage function you can download images from registry (e.g., docker.io)
### Operations on containers:
```sh
$ sudo lcrc ps -a # list containers
# create a container 'ubuntu1' with the directory
$ sudo lcrc create -n ubuntu1 --external-rootfs $HOME/myrootfs/ none
# or, you can create a container with OverlayFS
$ sudo mkdir $HOME/upperdir/ # create the upperdir for OverlayFS
$ sudo lcrc create -n 'ubuntu1' --external-rootfs overlayfs:$HOME/myrootfs:$HOME/upperdir none
$ sudo lcrc start ubuntu1 # start the container 'ubuntu1'
$ sudo lcrc kill ubuntu1 # kill the container 'ubuntu1'
```

0
docs/limitations.md Normal file
View File

187
iSulad.spec Normal file
View File

@ -0,0 +1,187 @@
%global _version 1.0.31
%global _release 20190919.232053.gitf0f8c706
%global is_systemd 1
%global debug_package %{nil}
Name: iSulad
Version: %{_version}
Release: %{_release}%{?dist}
Summary: Lightweight Container Runtime Daemon
License: Mulan PSL v1
BuildRoot: {_tmppath}/%{name}-%{version}
ExclusiveArch: x86_64 aarch64
URL: http://code.huawei.com/containers/lcrd
Source: %{name}-1.0.tar.gz
%ifarch x86_64 aarch64
Provides: libhttpclient.so()(64bit)
Provides: liblcrc.so()(64bit)
%endif
%if 0%{?is_systemd}
# Systemd 230 and up no longer have libsystemd-journal
BuildRequires: pkgconfig(systemd)
Requires: systemd-units
%else
Requires(post): chkconfig
Requires(preun): chkconfig
# This is for /sbin/service
Requires(preun): initscripts
%endif
BuildRequires: cmake gcc-c++ lxc lxc-devel lcr yajl yajl-devel clibcni-devel
BuildRequires: grpc grpc-devel protobuf-devel grpc-plugins
BuildRequires: libsecurec libsecurec-devel libcurl libcurl-devel sqlite-devel
BuildRequires: http-parser-devel libevhtp-devel libevent-devel
BuildRequires: libseccomp-devel libcap-devel libwebsockets libwebsockets-devel
BuildRequires: systemd-devel git
Requires: iSulad-kit lcr lxc clibcni
Requires: grpc protobuf yajl
Requires: libcurl libsecurec
Requires: sqlite http-parser libseccomp
Requires: libcap libwebsockets
Requires: libevhtp libevent systemd
%description
This is a umbrella project for gRPC-services based Lightweight Container
Runtime Daemon, written by C.
%prep
%autosetup -c -n %{name}-%{version}
%build
mkdir -p build
cd build
%cmake -DDEBUG=OFF -DLIB_INSTALL_DIR=%{_libdir} -DCMAKE_INSTALL_PREFIX=/usr ../
%make_build
%install
rm -rf %{buildroot}
cd build
install -d $RPM_BUILD_ROOT/%{_libdir}
install -m 0644 ./src/liblcrc.so %{buildroot}/%{_libdir}/liblcrc.so
install -m 0644 ./src/http/libhttpclient.so %{buildroot}/%{_libdir}/libhttpclient.so
install -d $RPM_BUILD_ROOT/%{_libdir}/pkgconfig
install -m 0640 ./conf/lcrd.pc %{buildroot}/%{_libdir}/pkgconfig/lcrd.pc
install -d $RPM_BUILD_ROOT/%{_bindir}
install -m 0755 ./src/lcrc %{buildroot}/%{_bindir}/lcrc
install -m 0755 ./src/lcrd %{buildroot}/%{_bindir}/lcrd
install -d $RPM_BUILD_ROOT/%{_includedir}/lcrd
install -m 0644 ../src/liblcrc.h %{buildroot}/%{_includedir}/lcrd/liblcrc.h
install -m 0644 ../src/connect/client/lcrc_connect.h %{buildroot}/%{_includedir}/lcrd/lcrc_connect.h
install -m 0644 ../src/container_def.h %{buildroot}/%{_includedir}/lcrd/container_def.h
install -m 0644 ../src/types_def.h %{buildroot}/%{_includedir}/lcrd/types_def.h
install -m 0644 ../src/error.h %{buildroot}/%{_includedir}/lcrd/error.h
install -m 0644 ../src/engines/engine.h %{buildroot}/%{_includedir}/lcrd/engine.h
install -d $RPM_BUILD_ROOT/%{_sysconfdir}/isulad
install -m 0640 ../src/contrib/config/daemon.json %{buildroot}/%{_sysconfdir}/isulad/daemon.json
install -m 0640 ../src/contrib/config/seccomp_default.json %{buildroot}/%{_sysconfdir}/isulad/seccomp_default.json
install -d $RPM_BUILD_ROOT/%{_sysconfdir}/default/lcrd
install -m 0640 ../src/contrib/config/config.json %{buildroot}/%{_sysconfdir}/default/lcrd/config.json
install -m 0550 ../src/contrib/sysmonitor/isulad-check.sh %{buildroot}/%{_sysconfdir}/default/lcrd/isulad-check.sh
mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sysmonitor/process
cp ../src/contrib/sysmonitor/isulad-monit $RPM_BUILD_ROOT/etc/sysmonitor/process
install -d $RPM_BUILD_ROOT/%{_sysconfdir}/default/lcrd/hooks
install -m 0640 ../src/contrib/config/hooks/default.json %{buildroot}/%{_sysconfdir}/default/lcrd/hooks/default.json
install -d $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig
install -p -m 0640 ../src/contrib/config/iSulad.sysconfig $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/iSulad
%if 0%{?is_systemd}
install -d $RPM_BUILD_ROOT/%{_unitdir}
install -p -m 0640 ../src/contrib/init/lcrd.service $RPM_BUILD_ROOT/%{_unitdir}/lcrd.service
%else
install -d $RPM_BUILD_ROOT/%{_initddir}
install -p -m 0640 ../src/contrib/init/lcrd.init $RPM_BUILD_ROOT/%{_initddir}/lcrd.init
%endif
%clean
rm -rf %{buildroot}
%post
if ! getent group lcrd > /dev/null; then
groupadd --system lcrd
fi
if [ "$1" = "1" ]; then
%if 0%{?is_systemd}
systemctl enable lcrd
systemctl start lcrd
%else
/sbin/chkconfig --add lcrd
%endif
elif [ "$1" = "2" ]; then
%if 0%{?is_systemd}
systemctl status lcrd | grep 'Active:' | grep 'running'
if [ $? -eq 0 ]; then
systemctl restart lcrd
fi
%else
/sbin/service lcrd status | grep 'Active:' | grep 'running'
if [ $? -eq 0 ]; then
/sbin/service lcrd restart
fi
%endif
fi
if ! getent group lcrd > /dev/null; then
groupadd --system lcrd
fi
%preun
%if 0%{?is_systemd}
%systemd_preun lcrd
%else
if [ $1 -eq 0 ] ; then
/sbin/service lcrd stop >/dev/null 2>&1
/sbin/chkconfig --del lcrd
fi
%endif
%postun
%if 0%{?is_systemd}
%systemd_postun_with_restart lcrd
%else
if [ "$1" -ge "1" ] ; then
/sbin/service lcrd condrestart >/dev/null 2>&1 || :
fi
%endif
%files
%attr(0600,root,root) %{_sysconfdir}/sysmonitor/process/isulad-monit
%attr(0550,root,root) %{_sysconfdir}/default/lcrd/isulad-check.sh
%defattr(0640,root,root,0750)
%{_sysconfdir}/isulad/*
%{_sysconfdir}/default/*
%defattr(-,root,root,-)
%if 0%{?is_systemd}
%{_unitdir}/lcrd.service
%attr(0640,root,root) %{_unitdir}/lcrd.service
%else
%{_initddir}/lcrd.init
%attr(0640,root,root) %{_initddir}/lcrd.init
%endif
%{_includedir}/lcrd/*
%attr(0755,root,root) %{_libdir}/pkgconfig
%attr(0640,root,root) %{_libdir}/pkgconfig/lcrd.pc
%defattr(0550,root,root,0750)
%{_bindir}/*
%{_libdir}/*
%attr(0640,root,root) %{_sysconfdir}/sysconfig/iSulad
%attr(0640,root,root) %{_sysconfdir}/isulad/daemon.json
%config(noreplace,missingok) %{_sysconfdir}/sysconfig/iSulad
%config(noreplace,missingok) %{_sysconfdir}/isulad/daemon.json
%if 0%{?is_systemd}
%config(noreplace,missingok) %{_unitdir}/lcrd.service
%else
%config(noreplace,missingok) %{_initddir}/lcrd.init
%endif

12
lcrd.pc.in Normal file
View File

@ -0,0 +1,12 @@
prefix=@CMAKE_INSTALL_PREFIX@
libdir=@CMAKE_INSTALL_PREFIX@/lib
localstatedir=@CMAKE_INSTALL_PREFIX@/var
includedir=@CMAKE_INSTALL_PREFIX@/include
Name: liblcrc
Description: light-weighted container runtime daemon library
Version: @LCRD_VERSION@
URL: http://code.huawei.com/containers/iSulad
Libs: -L@CMAKE_INSTALL_PREFIX@/lib -llcrc
Cflags: -I@CMAKE_INSTALL_PREFIX@/include

215
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,215 @@
# generate .c and .h to analyse json file
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/json)
# get json generate source files
aux_source_directory(${CMAKE_BINARY_DIR}/json generatesrcs)
message("-- Get generate srcs: " ${generatesrcs})
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/json/schema/src commonjsonsrcs)
message("-- Get common json srcs: " ${commonjsonsrcs})
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/json topjsonsrcs)
message("-- Get top json srcs: " ${topjsonsrcs})
list(APPEND JSON_FILES ${generatesrcs} ${commonjsonsrcs} ${topjsonsrcs})
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}
${CURL_INCLUDE_DIR}
${SYSTEMD_INCLUDE_DIR}
)
if (GRPC_CONNECTOR)
list(APPEND CHECKED_INCLUDE_DIRS
${GRPC_INCLUDE_DIR}
${CLIBCNI_INCLUDE_DIR}
${WEBSOCKET_INCLUDE_DIR}
)
else()
list(APPEND CHECKED_INCLUDE_DIRS
${SQLIT3_INCLUDE_DIR}
${EVENT_INCLUDE_DIR}
${EVHTP_INCLUDE_DIR}
)
endif()
list(REMOVE_DUPLICATES CHECKED_INCLUDE_DIRS)
set(SHARED_INCS
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/cutils
${CMAKE_CURRENT_SOURCE_DIR}/sha256
${CMAKE_CURRENT_SOURCE_DIR}/tar
${CMAKE_CURRENT_SOURCE_DIR}/console
${CMAKE_CURRENT_SOURCE_DIR}/json
${CMAKE_CURRENT_SOURCE_DIR}/json/schema/src
${CMAKE_BINARY_DIR}/json
${CMAKE_BINARY_DIR}/conf
${CHECKED_INCLUDE_DIRS}
)
add_subdirectory(tar)
add_subdirectory(sha256)
add_subdirectory(cutils)
add_subdirectory(console)
set(SHARED_SRCS
${JSON_FILES}
${TAR_SRCS}
${SHA256_SRCS}
${CUTILS_SRCS}
${CONSOLE_SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/container_def.c
${CMAKE_CURRENT_SOURCE_DIR}/types_def.c
${CMAKE_CURRENT_SOURCE_DIR}/error.c
${CMAKE_CURRENT_SOURCE_DIR}/path.c
${CMAKE_CURRENT_SOURCE_DIR}/log.c
${CMAKE_CURRENT_SOURCE_DIR}/mainloop.c
)
# get all c and header files
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/connect)
if (GRPC_CONNECTOR)
# GRPC
aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/types CONNECT_API_TYPES)
aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/containers CONNECT_API_CONTAINERS)
aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/images CONNECT_API_IMAGES)
aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/cri CONNECT_API_CRI)
set(CONNECT_API ${CONNECT_API_TYPES} ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_CRI})
list(APPEND SHARED_INCS
${CMAKE_BINARY_DIR}/grpc/src/api/types
${CMAKE_BINARY_DIR}/grpc/src/api/services/containers
${CMAKE_BINARY_DIR}/grpc/src/api/services/images
${CMAKE_BINARY_DIR}/grpc/src/api/services/cri
${CMAKE_CURRENT_SOURCE_DIR}/cpputils
)
add_subdirectory(cpputils)
add_subdirectory(websocket)
list(APPEND SHARED_SRCS ${CPPUTILS_SRCS})
else()
list(APPEND SHARED_INCS
${CMAKE_CURRENT_SOURCE_DIR}/api/services/containers/rest
${CMAKE_CURRENT_SOURCE_DIR}/api/services/images/rest
)
endif()
list(APPEND SHARED_SRCS ${CONNECT_API} ${CPPUTILS_SRCS})
list(REMOVE_DUPLICATES SHARED_INCS)
list(REMOVE_DUPLICATES SHARED_SRCS)
add_subdirectory(http)
# ------ build liblcrc ------
if (OPENSSL_VERIFY)
list(APPEND CONNECTOR ${CMAKE_CURRENT_SOURCE_DIR}/http/certificate.c)
endif()
add_library(liblcrc ${LIBTYPE}
${CMAKE_CURRENT_SOURCE_DIR}/liblcrc.c
${CMAKE_CURRENT_SOURCE_DIR}/pack_config.c
${CONNECTOR}
${SHARED_SRCS}
)
target_include_directories(liblcrc PUBLIC
${SHARED_INCS}
${CONNECTOR_INCS}
${CMAKE_CURRENT_SOURCE_DIR}/http
)
# set liblcrc FLAGS
set_target_properties(liblcrc PROPERTIES PREFIX "")
target_link_libraries(liblcrc ${LIBYAJL_LIBRARY} ${LIBSECUREC_LIBRARY})
if (GRPC_CONNECTOR)
target_link_libraries(liblcrc -Wl,--as-needed -lstdc++ -lcrypto)
target_link_libraries(liblcrc -Wl,--as-needed ${PROTOBUF_LIBRARY})
target_link_libraries(liblcrc -Wl,--no-as-needed ${GRPC_PP_REFLECTION_LIBRARY} ${GRPC_PP_LIBRARY} ${GRPC_LIBRARY} ${GPR_LIBRARY})
else()
target_link_libraries(liblcrc ${EVHTP_LIBRARY} ${EVENT_LIBRARY} ${ZLIB_LIBRARY} -ldl libhttpclient)
endif()
# ------ build liblcrc finish -----
add_subdirectory(cmd)
# ------ build lcrc -------
add_executable(lcrc
${LCRC_SRCS}
)
target_include_directories(lcrc PUBLIC ${LCRC_INCS} ${SHARED_INCS})
target_link_libraries(lcrc liblcrc -lpthread)
# ------ build lcrc finish -------
# ------ build lcrd -------
add_subdirectory(services)
add_subdirectory(image)
add_subdirectory(engines)
add_subdirectory(plugin)
add_subdirectory(map)
add_subdirectory(config)
add_executable(lcrd
${CONNECT_SOCKET} ${SHARED_SRCS}
${LCRD_SRCS} ${SERVICES_SRCS}
${HTTP_SRCS}
${ENGINES_SRCS}
${IMAGE_SRCS}
${PLUGIN_SRCS}
${MAP_SRCS} ${CONFIG_SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/filters.c
${CMAKE_CURRENT_SOURCE_DIR}/namespace.c
${CMAKE_CURRENT_SOURCE_DIR}/liblcrd.c
${CMAKE_CURRENT_SOURCE_DIR}/sysctl_tools.c
${WEBSOCKET_SERVICE_SRCS}
)
target_include_directories(lcrd PUBLIC
${SHARED_INCS}
${CONNECT_SOCKET_INCS}
${SERVICES_INCS}
${IMAGE_INCS}
${ENGINES_INCS}
${LCRD_INCS}
${CMAKE_CURRENT_SOURCE_DIR}/plugin
${CMAKE_CURRENT_SOURCE_DIR}/map
${CMAKE_CURRENT_SOURCE_DIR}/config
${CMAKE_CURRENT_SOURCE_DIR}/http
${WEBSOCKET_SERVICE_INCS}
)
target_link_libraries(lcrd ${LIBYAJL_LIBRARY} ${LIBSECUREC_LIBRARY} ${SYSTEMD_LIBRARY})
target_link_libraries(lcrd -ldl ${ZLIB_LIBRARY} -lpthread libhttpclient)
if (ENABLE_EMBEDDED)
target_link_libraries(lcrd ${SQLITE3_LIBRARY})
endif()
if (GRPC_CONNECTOR)
message("GRPC iSulad")
target_link_libraries(lcrd -Wl,--as-needed -lstdc++ -lcrypto)
target_link_libraries(lcrd -Wl,--as-needed ${PROTOBUF_LIBRARY})
target_link_libraries(lcrd -Wl,--no-as-needed ${GRPC_PP_REFLECTION_LIBRARY} ${GRPC_PP_LIBRARY} ${GRPC_LIBRARY} ${GPR_LIBRARY})
target_link_libraries(lcrd ${CLIBCNI_LIBRARY} ${WEBSOCKET_LIBRARY})
else()
message("Restful iSulad")
target_link_libraries(lcrd ${EVHTP_LIBRARY} ${EVENT_LIBRARY})
endif()
if (ISULAD_GCOV)
target_link_libraries(lcrc -lgcov)
target_link_libraries(liblcrc -lgcov)
target_link_libraries(lcrd -lgcov)
endif()
# ------ build lcrd finish -------
# ------ install binary --------
install(TARGETS liblcrc
LIBRARY DESTINATION ${LIB_INSTALL_DIR_DEFAULT} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
install(TARGETS lcrc
RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
install(TARGETS lcrd
RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)

View File

@ -0,0 +1,447 @@
syntax = "proto3";
option optimize_for = CODE_SIZE;
import "google/protobuf/timestamp.proto";
package containers;
enum ContainerStatus {
UNKNOWN = 0;
CREATED = 1;
STARTING = 2;
RUNNING = 3;
STOPPED = 4;
PAUSED = 5;
RESTARTING = 6;
}
enum EventType {
EXIT = 0;
STOPPED1 = 1;
STARTING1 = 2;
RUNNING1 = 3;
STOPPING = 4;
ABORTING = 5;
FREEZING = 6;
FROZEN = 7;
THAWED = 8;
OOM = 9;
CREATE = 10;
START = 11;
EXEC_ADDED = 12;
PAUSED1 = 13;
}
message Container {
string id = 1;
int32 pid = 2;
ContainerStatus status = 3;
string interface = 4;
string ipv4 = 5;
string ipv6 = 6;
string image = 7;
string command = 8;
double ram = 9;
double swap = 10;
uint32 exit_code = 11;
uint64 restartcount = 12;
string startat = 13;
string finishat = 14;
string runtime = 15;
string name = 16;
string health_state = 17;
}
message Container_info {
string id = 1;
int32 pid = 2;
ContainerStatus status = 3;
uint64 pids_current = 4;
uint64 cpu_use_nanos = 5;
uint64 cpu_use_user = 6;
uint64 cpu_use_kernel = 7;
uint64 cpu_system_use = 8;
uint32 online_cpus = 9;
uint64 blkio_read = 10;
uint64 blkio_write = 11;
uint64 mem_used = 12;
uint64 mem_limit = 13;
uint64 kmem_used = 14;
uint64 kmem_limit = 15;
}
message Event {
string id = 1;
EventType type = 2;
int32 pid = 3;
uint32 exit_status = 4;
google.protobuf.Timestamp timestamp = 5;
}
service ContainerService {
rpc Create(CreateRequest) returns (CreateResponse);
rpc Start(StartRequest) returns (StartResponse);
rpc RemoteStart(stream RemoteStartRequest) returns (stream RemoteStartResponse);
rpc Top(TopRequest) returns (TopResponse);
rpc Stop(StopRequest) returns (StopResponse);
rpc Kill(KillRequest) returns (KillResponse);
rpc Delete(DeleteRequest) returns (DeleteResponse);
rpc Pause(PauseRequest) returns (PauseResponse);
rpc Resume(ResumeRequest) returns (ResumeResponse);
rpc Inspect(InspectContainerRequest) returns (InspectContainerResponse);
rpc List(ListRequest) returns (ListResponse);
rpc Stats(StatsRequest) returns (StatsResponse);
rpc Wait(WaitRequest) returns (WaitResponse);
rpc Events(EventsRequest) returns (stream Event);
rpc Exec(ExecRequest) returns (ExecResponse);
rpc RemoteExec(stream RemoteExecRequest) returns (stream RemoteExecResponse);
rpc Version(VersionRequest) returns (VersionResponse);
rpc Info(InfoRequest) returns (InfoResponse);
rpc Update(UpdateRequest) returns (UpdateResponse);
rpc Attach(stream AttachRequest) returns (stream AttachResponse);
rpc Container_conf(Container_conf_Request) returns (Container_conf_Response);
rpc Restart(RestartRequest) returns (RestartResponse);
rpc Export(ExportRequest) returns (ExportResponse);
rpc CopyFromContainer(CopyFromContainerRequest) returns (stream CopyFromContainerResponse);
rpc CopyToContainer(stream CopyToContainerRequest) returns (stream CopyToContainerResponse);
rpc Rename(RenameRequest) returns (RenameResponse);
rpc Logs(LogsRequest) returns (stream LogsResponse);
}
message CreateRequest {
string id = 1;
string rootfs = 2;
// Image contains the reference of the image used to build the
// specification and snapshots for running this container.
//
string image = 3;
string runtime = 4;
string hostconfig = 5;
string customconfig = 6;
}
message CreateResponse {
string id = 1;
int32 pid = 2;
uint32 cc = 3;
string errmsg = 4;
}
message StartRequest {
string id = 1;
string stdin = 2;
bool attach_stdin = 3;
string stdout = 4;
bool attach_stdout = 5;
string stderr = 6;
bool attach_stderr = 7;
}
message StartResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message RemoteStartRequest {
bytes stdin = 1;
bool finish = 2;
}
message RemoteStartResponse {
bytes stdout = 1;
bytes stderr = 2;
bool finish = 3;
}
message TopRequest {
string id = 1;
repeated string args = 2;
}
message TopResponse {
bytes titles = 1;
repeated bytes processes = 2;
uint32 cc = 3;
string errmsg = 4;
}
message StopRequest {
string id = 1;
bool force = 2;
int32 timeout = 3;
}
message StopResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message RestartRequest {
string id = 1;
int32 timeout = 2;
}
message RestartResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message KillRequest {
string id = 1;
uint32 signal = 2;
}
message KillResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message DeleteRequest {
string id = 1;
bool force = 2;
}
message DeleteResponse {
string id = 1;
uint32 exit_status = 2;
uint32 cc = 3;
string errmsg = 4;
}
message PauseRequest {
string id = 1;
}
message PauseResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message ResumeRequest {
string id = 1;
}
message ResumeResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message InspectContainerRequest {
string id = 1;
bool bformat = 2;
int32 timeout = 3;
}
message InspectContainerResponse {
string ContainerJSON = 1;
uint32 cc = 2;
string errmsg = 3;
}
message ListRequest {
map<string, string> filters = 1;
bool all = 2;
}
message ListResponse {
repeated Container containers = 1;
uint32 cc = 2;
string errmsg = 3;
}
message StatsRequest {
string runtime = 1;
repeated string containers = 2;
bool all = 3;
}
message StatsResponse {
repeated Container_info containers = 1;
uint32 cc = 2;
string errmsg = 3;
}
message WaitRequest {
string id = 1;
uint32 condition = 2;
}
message WaitResponse {
uint32 cc = 1;
uint32 exit_code = 2;
string errmsg = 3;
}
message EventsRequest {
google.protobuf.Timestamp since = 1;
google.protobuf.Timestamp until = 2;
bool storeOnly = 3;
string id = 4;
}
message ExecRequest {
// ContainerID specifies the container in which to exec the process.
string container_id = 1;
bool tty = 2;
bool open_stdin = 3;
bool attach_stdin = 4;
bool attach_stdout = 5;
bool attach_stderr = 6;
string stdin = 7;
string stdout = 8;
string stderr = 9;
repeated string argv = 10;
repeated string env = 11;
}
message ExecResponse {
int32 pid = 1;
uint32 exit_code = 2;
uint32 cc = 3;
string errmsg = 4;
}
message RemoteExecRequest {
repeated bytes cmd = 1;
bool finish = 2;
}
message RemoteExecResponse {
bytes stdout = 1;
bool finish = 2;
}
message AttachRequest {
bytes stdin = 1;
bool finish = 2;
}
message AttachResponse {
bytes stdout = 1;
bytes stderr = 2;
bool finish = 3;
}
message VersionRequest {
}
message VersionResponse {
string version = 1;
string git_commit = 2;
string build_time = 3;
string root_path = 4;
uint32 cc = 5;
string errmsg = 6;
}
message InfoRequest {
}
message InfoResponse {
uint32 cc = 1;
string errmsg = 2;
string version = 3;
uint32 containers_num = 4;
uint32 c_running = 5;
uint32 c_paused = 6;
uint32 c_stopped = 7;
uint32 images_num = 8;
string kversion = 9;
string os_type = 10;
string architecture = 11;
string nodename = 12;
uint32 cpus = 13;
string operating_system = 14;
string cgroup_driver = 15;
string logging_driver = 16;
string huge_page_size = 17;
string isulad_root_dir = 18;
uint32 total_mem = 19;
string http_proxy = 20;
string https_proxy = 21;
string no_proxy = 22;
}
message UpdateRequest {
string id = 1;
string hostconfig = 2;
}
message UpdateResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message Container_conf_Request {
// ContainerID specifies the container in which to get config.
string container_id = 1;
string runtime = 2;
}
message Container_conf_Response {
string container_logpath = 1;
string container_logsize = 2;
uint32 container_logrotate = 3;
uint32 cc = 4;
string errmsg = 5;
}
message ExportRequest {
string id = 1;
string file = 2;
}
message ExportResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message CopyFromContainerRequest {
string id = 1;
string runtime = 2;
string srcpath = 3;
}
message CopyFromContainerResponse {
bytes data = 1;
}
message CopyToContainerRequest {
bytes data = 1;
}
message CopyToContainerResponse {
bool finish = 1;
}
message RenameRequest {
string oldname = 1;
string newname = 2;
}
message RenameResponse {
string id = 1;
uint32 cc = 2;
string errmsg = 3;
}
message LogsRequest {
string id = 1;
string runtime = 2;
string since = 3;
string until = 4;
bool timestamps = 5;
bool follow = 6;
int64 tail = 7;
bool details = 8;
}
message LogsResponse {
bytes data = 1;
string stream = 2;
string time = 3;
bytes attrs = 4;
}

View File

@ -0,0 +1,84 @@
/******************************************************************************
* 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: tanyifeng
* Create: 2018-11-22
* Description: provide container rest definition
**********************************************************************************/
#ifndef CONTAINER_REST_H_
#define CONTAINER_REST_H_
#include "container_create_request.h"
#include "container_create_response.h"
#include "container_start_request.h"
#include "container_start_response.h"
#include "container_stop_request.h"
#include "container_stop_response.h"
#include "container_restart_request.h"
#include "container_restart_response.h"
#include "container_pause_request.h"
#include "container_pause_response.h"
#include "container_kill_request.h"
#include "container_kill_response.h"
#include "container_update_request.h"
#include "container_update_response.h"
#include "container_version_request.h"
#include "container_version_response.h"
#include "container_exec_request.h"
#include "container_exec_response.h"
#include "container_delete_request.h"
#include "container_delete_response.h"
#include "container_inspect_request.h"
#include "container_inspect_response.h"
#include "container_list_request.h"
#include "container_list_response.h"
#include "container_attach_request.h"
#include "container_attach_response.h"
#include "container_resume_request.h"
#include "container_resume_response.h"
#include "container_wait_request.h"
#include "container_wait_response.h"
#include "container_conf_request.h"
#include "container_conf_response.h"
#ifndef RestHttpHead
#define RestHttpHead "http://localhost"
#endif
#define ContainerServiceCreate "/ContainerService/Create"
#define ContainerServiceStart "/ContainerService/Start"
#define ContainerServiceRestart "/ContainerService/Restart"
#define ContainerServiceStop "/ContainerService/Stop"
#define ContainerServiceVersion "/ContainerService/Version"
#define ContainerServiceUpdate "/ContainerService/Update"
#define ContainerServicePause "/ContainerService/Pause"
#define ContainerServiceKill "/ContainerService/Kill"
#define ContainerServiceExec "/ContainerService/Exec"
#define ContainerServiceRemove "/ContainerService/Remove"
#define ContainerServiceInspect "/ContainerService/Inspect"
#define ContainerServiceList "/ContainerService/List"
#define ContainerServiceAttach "/ContainerService/Attach"
#define ContainerServiceResume "/ContainerService/Resume"
#define ContainerServiceWait "/ContainerService/Wait"
#define ContainerServiceConf "/ContainerService/Container_conf"
/* "/ContainerService/Kill",
"/ContainerService/Delete",
"/ContainerService/Pause",
"/ContainerService/Info",
"/ContainerService/Inspect",
"/ContainerService/Stats",
"/ContainerService/Events",
"/ContainerService/Exec",
"/ContainerService/Version",
"/ContainerService/Update",
"/ContainerService/Attach",
*/
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
syntax = "proto3";
option optimize_for = CODE_SIZE;
message HealthCheckRequest {
string service = 1;
}
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
}
ServingStatus status = 1;
}
service HealthService{
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
}

View File

@ -0,0 +1,137 @@
syntax = "proto3";
option optimize_for = CODE_SIZE;
import "google/protobuf/timestamp.proto";
import "descriptor.proto";
package images;
// Images is a service that allows one to register images with containerd.
//
// In containerd, an image is merely the mapping of a name to a content root,
// described by a descriptor. The behavior and state of image is purely
// dictated by the type of the descriptor.
//
// From the perspective of this service, these references are mostly shallow,
// in that the existence of the required content won't be validated until
// required by consuming services.
//
// As such, this can really be considered a "metadata service".
service ImagesService {
// List returns a list of all images known to containerd.
rpc List(ListImagesRequest) returns (ListImagesResponse);
// Delete deletes the image by name.
rpc Delete(DeleteImageRequest) returns (DeleteImageResponse);
// load image from archive.
rpc Load(LoadImageRequest) returns (LoadImageResponse);
//inspect image
rpc Inspect(InspectImageRequest) returns (InspectImageResponse);
// Login to a Docker registry
rpc Login(LoginRequest) returns (LoginResponse);
// Logout from a Docker registry
rpc Logout(LogoutRequest) returns (LogoutResponse);
}
message Image {
// Name provides a unique name for the image.
//
// Containerd treats this as the primary identifier.
string name = 1;
// Labels provides free form labels for the image. These are runtime only
// and do not get inherited into the package image in any way.
//
// Labels may be updated using the field mask.
// The combined size of a key/value pair cannot exceed 4096 bytes.
map<string, string> labels = 2;
// Target describes the content entry point of the image.
containerd.types.Descriptor target = 3;
// CreatedAt is the time the image was first created.
google.protobuf.Timestamp created_at = 7;
// UpdatedAt is the last time the image was mutated.
google.protobuf.Timestamp updated_at = 8;
}
message ListImagesRequest {
// Filters contains one or more filters using the syntax defined in the
// containerd filter package.
//
// The returned result will be those that match any of the provided
// filters. Expanded, images that match the following will be
// returned:
//
// filters[0] or filters[1] or ... or filters[n-1] or filters[n]
//
// If filters is zero-length or nil, all items will be returned.
repeated string filters = 1;
}
message ListImagesResponse {
repeated Image images = 1;
uint32 cc = 2;
string errmsg = 3;
}
message DeleteImageRequest {
string name = 1;
bool force = 2;
}
message DeleteImageResponse {
string name = 1;
uint32 cc = 2;
string errmsg = 3;
}
message LoadImageRequest {
string file = 1;
string type = 2;
string tag = 3;
}
message LoadImageResponse {
uint32 cc = 1;
string errmsg = 2;
}
message InspectImageRequest {
string id = 1;
bool bformat = 2;
int32 timeout = 3;
}
message InspectImageResponse {
string ImageJSON = 1;
uint32 cc = 2;
string errmsg = 3;
}
message LoginRequest {
string username = 1;
string password = 2;
string server = 3;
string type = 4;
}
message LoginResponse {
uint32 cc = 1;
string errmsg = 2;
}
message LogoutRequest {
string server = 1;
string type = 2;
}
message LogoutResponse {
uint32 cc = 1;
string errmsg = 2;
}

View File

@ -0,0 +1,36 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: maoweiyong
* Create: 2017-11-22
* Description: provide container image rest definition
********************************************************************************/
#ifndef IMAGE_REST_H_
#define IMAGE_REST_H_
#include "image_load_image_request.h"
#include "image_load_image_response.h"
#include "image_list_images_request.h"
#include "image_list_images_response.h"
#include "image_delete_image_request.h"
#include "image_delete_image_response.h"
#include "image_inspect_request.h"
#include "image_inspect_response.h"
#ifndef RestHttpHead
#define RestHttpHead "http://localhost"
#endif
#define ImagesServiceLoad "/ImagesService/Load"
#define ImagesServiceList "/ImagesService/List"
#define ImagesServiceDelete "/ImagesService/Delete"
#define ImagesServiceInspect "/ImagesService/Inspect"
#endif

View File

@ -0,0 +1,15 @@
syntax = "proto3";
option optimize_for = CODE_SIZE;
package containerd.types;
// Descriptor describes a blob in a content store.
//
// This descriptor can be used to reference content from an
// oci descriptor found in a manifest.
// See https://godoc.org/github.com/opencontainers/image-spec/specs-go/v1#Descriptor
message Descriptor {
string media_type = 1;
string digest = 2;
int64 size = 3;
}

10
src/cmd/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
# get current directory sources files
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} comm_srcs)
add_subdirectory(lcrc)
set(LCRC_SRCS ${comm_srcs} ${CMD_LCRC_SRCS} PARENT_SCOPE)
set(LCRC_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_LCRC_INCS} PARENT_SCOPE)
add_subdirectory(lcrd)
set(LCRD_SRCS ${comm_srcs} ${CMD_LCRD_SRCS} PARENT_SCOPE)
set(LCRD_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_LCRD_INCS} PARENT_SCOPE)

816
src/cmd/commander.c Normal file
View File

@ -0,0 +1,816 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: tanyifeng
* Create: 2017-11-22
* Description: provide command functions
******************************************************************************/
#define _GNU_SOURCE
#include "commander.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <regex.h>
#include <limits.h>
#include "securec.h"
#include "liblcrd.h"
#include "utils.h"
#include "log.h"
void command_help_lcrd_head()
{
fprintf(stdout, "lcrd\n\nlightweight container runtime daemon\n");
}
int compare_options(const void *s1, const void *s2)
{
return strcmp((*(const command_option_t *)s1).large, (*(const command_option_t *)s2).large);
}
void print_options(int options_len, const command_option_t *options)
{
int i = 0;
int max_opt_len = 0;
for (i = 0; i < options_len; i++) {
command_option_t option = options[i];
// -s
int len = 2;
// -s, --large, 6 is the length of "-s, --".
if (option.large != NULL) {
len = (int)(strlen(option.large) + 6);
}
if (len > max_opt_len) {
max_opt_len = len;
}
}
// format: " -s, --large description"
// 6 is the total length of black before "-s" and "description"
max_opt_len += 6;
for (i = 0; i < options_len; i++) {
command_option_t option = options[i];
int curindex = 0;
int space_left = 0;
curindex = fprintf(stdout, " ");
if (option.small) {
curindex += fprintf(stdout, "-%c", (char)option.small);
}
if (option.large != NULL) {
if (option.small) {
curindex += fprintf(stdout, ", --%s", option.large);
} else {
curindex += fprintf(stdout, " --%s", option.large);
}
}
if (curindex <= max_opt_len) {
space_left = max_opt_len - curindex;
}
fprintf(stdout, "%*s%s\n", space_left, "", option.description);
}
fputc('\n', stdout);
}
void command_help(command_t *self)
{
const char *progname = strrchr(self->name, '/');
if (progname == NULL) {
progname = self->name;
} else {
progname++;
}
if (self->type != NULL && strcmp(self->type, "lcrd") == 0) {
command_help_lcrd_head();
}
fprintf(stdout, "\nUsage: %s %s\n\n", progname, self->usage);
fprintf(stdout, "%s\n\n", self->description);
qsort(self->options, (size_t)self->option_count, sizeof(self->options[0]), compare_options);
print_options(self->option_count, self->options);
}
int command_valid_socket(command_option_t *option, const char *arg)
{
if (!util_validate_socket(arg)) {
COMMAND_ERROR("Invalid socket name : %s", arg);
return -1;
}
return 0;
}
void command_init(command_t *self, command_option_t *opts, int opts_len, int argc, const char **argv,
const char *description, const char *usage)
{
if (memset_s(self, sizeof(command_t), 0, sizeof(command_t)) != EOK) {
COMMAND_ERROR("Failed to set memory");
return;
}
self->name = argv[0];
self->argc = argc - 2;
self->argv = argv + 2;
self->usage = usage;
self->description = description;
self->options = opts;
self->option_count = opts_len;
}
void command_option(command_t *self, command_option_type_t type, void *data, int small, const char *large,
const char *desc, command_callback_t cb)
{
if (self->option_count == COMMANDER_MAX_OPTIONS) {
COMMAND_ERROR("Maximum option definitions exceeded");
exit(EINVALIDARGS);
}
int n = self->option_count++;
command_option_t *opt = &self->options[n];
opt->type = type;
opt->data = data;
opt->cb = cb;
opt->small = small;
opt->description = desc;
opt->large = large;
}
static int read_option_arg(command_t *self, command_option_t *opt, const char **opt_arg, const char **readed)
{
if (self == NULL || opt == NULL || opt_arg == NULL) {
return -1;
}
if (opt->hasdata) {
*readed = *opt_arg;
*opt_arg = NULL;
}
if (!opt->hasdata && self->argc > 1) {
opt->hasdata = true;
*readed = *++self->argv;
self->argc--;
}
if (!opt->hasdata) {
COMMAND_ERROR("Flag needs an argument: --%s", opt->large);
return -1;
}
return 0;
}
static int command_get_bool_option_data(command_option_t *option, const char **opt_arg)
{
bool converted_bool = (option->type == CMD_OPT_TYPE_BOOL) ? true : false;
if (option->hasdata) {
int ret = util_str_to_bool(*opt_arg, &converted_bool);
if (ret != 0) {
COMMAND_ERROR("Invalid boolean value \"%s\" for flag --%s", *opt_arg, option->large);
return -1;
}
*opt_arg = NULL;
}
*(bool *)option->data = converted_bool;
return 0;
}
static int command_get_string_option_data(command_t *self, command_option_t *option, const char **opt_arg)
{
if (read_option_arg(self, option, opt_arg, (const char **)option->data)) {
return -1;
}
if (option->cb != NULL) {
return option->cb(option, *(char **)option->data);
}
return 0;
}
static int command_get_string_dup_option_data(command_t *self, command_option_t *option, const char **opt_arg)
{
const char *readed_item = NULL;
if (read_option_arg(self, option, opt_arg, &readed_item) != 0) {
return -1;
}
if (*(char **)option->data != NULL) {
free(*(char **)option->data);
}
*(char **)option->data = util_strdup_s(readed_item);
if (option->cb != NULL) {
return option->cb(option, readed_item);
}
return 0;
}
static int command_get_callback_option_data(command_t *self, command_option_t *option, const char **opt_arg)
{
const char *readed_item = NULL;
if (read_option_arg(self, option, opt_arg, &readed_item)) {
return -1;
}
if (option->cb == NULL) {
COMMAND_ERROR("Must specify callback for type array");
return -1;
}
return option->cb(option, readed_item);
}
static int command_get_option_data(command_t *self, command_option_t *option, const char **opt_arg)
{
if (option == NULL) {
return -1;
}
switch (option->type) {
case CMD_OPT_TYPE_BOOL:
case CMD_OPT_TYPE_BOOL_FALSE:
return command_get_bool_option_data(option, opt_arg);
case CMD_OPT_TYPE_STRING:
return command_get_string_option_data(self, option, opt_arg);
case CMD_OPT_TYPE_STRING_DUP:
return command_get_string_dup_option_data(self, option, opt_arg);
case CMD_OPT_TYPE_CALLBACK:
return command_get_callback_option_data(self, option, opt_arg);
default:
COMMAND_ERROR("Unkown command option type:%d", (int)(option->type));
return -1;
}
}
int have_short_options(command_t *self, char arg)
{
int i;
for (i = 0; i < self->option_count; i++) {
if (self->options[i].small == arg) {
return 0;
}
}
return -1;
}
static int command_parse_options(command_t *self, const char **opt_arg, bool *found)
{
int j = 0;
for (j = 0; j < self->option_count; ++j) {
command_option_t *opt = &self->options[j];
opt->hasdata = false;
if (opt->small != (*opt_arg)[0]) {
continue;
}
// match flag
*found = true;
if ((*opt_arg)[1]) {
if ((*opt_arg)[1] == '=') {
*opt_arg = *opt_arg + 2;
opt->hasdata = true;
} else {
*opt_arg = *opt_arg + 1;
}
} else {
*opt_arg = NULL;
}
if (command_get_option_data(self, opt, opt_arg)) {
return -1;
}
break;
}
return 0;
}
static int command_parse_short_arg(command_t *self, const char *arg)
{
bool found = false;
const char *opt_arg = arg;
do {
found = false;
if (opt_arg[0] == 'h' && have_short_options(self, 'h') < 0) {
command_help(self);
exit(0);
}
if (command_parse_options(self, &opt_arg, &found)) {
return -1;
}
} while (found && opt_arg != NULL);
if (opt_arg != NULL) {
COMMAND_ERROR("Unkown flag found:'%c'", opt_arg[0]);
exit(EINVALIDARGS);
}
return 0;
}
static int command_parse_long_arg(command_t *self, const char *arg)
{
int j = 0;
if (strcmp(arg, "help") == 0) {
command_help(self);
exit(0);
}
for (j = 0; j < self->option_count; ++j) {
command_option_t *opt = &self->options[j];
const char *opt_arg = NULL;
opt->hasdata = false;
if (opt->large == NULL) {
continue;
}
opt_arg = str_skip_str(arg, opt->large);
if (opt_arg == NULL) {
continue;
}
if (opt_arg[0]) {
if (opt_arg[0] != '=') {
continue;
}
opt_arg = opt_arg + 1;
opt->hasdata = true;
} else {
opt_arg = NULL;
}
if (command_get_option_data(self, opt, &opt_arg)) {
return -1;
}
return 0;
}
COMMAND_ERROR("Unkown flag found:'--%s'\n", arg);
exit(EINVALIDARGS);
}
int command_parse_args(command_t *self, int *argc, char * const **argv)
{
int ret = 0;
for (; self->argc; self->argc--, self->argv++) {
const char *arg_opt = self->argv[0];
if (arg_opt[0] != '-' || !arg_opt[1]) {
break;
}
// short option
if (arg_opt[1] != '-') {
arg_opt = arg_opt + 1;
ret = command_parse_short_arg(self, arg_opt);
if (!ret) {
continue;
}
break;
}
// --
if (!arg_opt[2]) {
self->argc--;
self->argv++;
break;
}
// long option
arg_opt = arg_opt + 2;
ret = command_parse_long_arg(self, arg_opt);
if (ret == 0) {
continue;
}
break;
}
if (self->argc > 0) {
*argc = self->argc;
*argv = (char * const *)self->argv;
}
return ret;
}
int command_valid_socket_append_array(command_option_t *option, const char *arg)
{
int len;
char **pos = NULL;
if (option == NULL) {
return -1;
}
if (!util_validate_socket(arg)) {
COMMAND_ERROR("Invalid socket name : %s", arg);
return -1;
}
for (pos = *(char ***)(option->data), len = 0; pos != NULL && *pos != NULL; pos++, len++) {
if (strcmp(*pos, arg) == 0) {
break;
}
}
if (pos != NULL && *pos != NULL) {
return 0;
}
if (util_array_append(option->data, arg) != 0) {
ERROR("merge hosts config failed");
return -1;
}
len++;
if (len > MAX_HOSTS) {
COMMAND_ERROR("Too many hosts, the max number is %d", MAX_HOSTS);
return -1;
}
return 0;
}
static int check_default_ulimit_input(const char *val)
{
int ret = 0;
if (val == NULL || strcmp(val, "") == 0) {
COMMAND_ERROR("ulimit argument can't be empty");
ret = -1;
goto out;
}
if (val[0] == '=' || val[strlen(val) - 1] == '=') {
COMMAND_ERROR("Invalid ulimit argument: \"%s\", delimiter '=' can't"
" be the first or the last character", val);
ret = -1;
}
out:
return ret;
}
static void get_default_ulimit_split_parts(const char *val, char ***parts, size_t *parts_len, char deli)
{
*parts = util_string_split_multi(val, deli);
if (*parts == NULL) {
ERROR("Out of memory");
return;
}
*parts_len = util_array_len(*parts);
}
static int parse_soft_hard_default_ulimit(const char *val, char **limitvals, size_t limitvals_len, int64_t *soft,
int64_t *hard)
{
int ret = 0;
// parse soft
ret = util_safe_llong(limitvals[0], (long long *)soft);
if (ret < 0) {
COMMAND_ERROR("Invalid ulimit soft value: \"%s\", parse int64 failed: %s", val, strerror(-ret));
ret = -1;
goto out;
}
// parse hard if exists
if (limitvals_len > 1) {
ret = util_safe_llong(limitvals[1], (long long *)hard);
if (ret < 0) {
COMMAND_ERROR("Invalid ulimit hard value: \"%s\", parse int64 failed: %s", val, strerror(-ret));
ret = -1;
goto out;
}
if (*soft > *hard) {
COMMAND_ERROR("Ulimit soft limit must be less than or equal to hard limit: %lld > %lld",
(long long int)(*soft), (long long int)(*hard));
ret = -1;
goto out;
}
} else {
*hard = *soft; // default to soft in case no hard was set
}
out:
return ret;
}
int check_default_ulimit_type(const char *type)
{
int ret = 0;
char **tmptype = NULL;
char *ulimit_valid_type[] = {
// "as", // Disabled since this doesn't seem usable with the way Docker inits a container.
"core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice",
"nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", "stack", NULL
};
for (tmptype = ulimit_valid_type; *tmptype != NULL; tmptype++) {
if (strcmp(type, *tmptype) == 0) {
break;
}
}
if (*tmptype == NULL) {
COMMAND_ERROR("Invalid ulimit type: %s", type);
ret = -1;
}
return ret;
}
static host_config_ulimits_element *parse_default_ulimit(const char *val)
{
int ret = 0;
int64_t soft = 0;
int64_t hard = 0;
size_t parts_len = 0;
size_t limitvals_len = 0;
char **parts = NULL;
char **limitvals = NULL;
host_config_ulimits_element *ulimit = NULL;
ret = check_default_ulimit_input(val);
if (ret != 0) {
return NULL;
}
get_default_ulimit_split_parts(val, &parts, &parts_len, '=');
if (parts == NULL) {
ERROR("Out of memory");
return NULL;
} else if (parts_len != 2) {
COMMAND_ERROR("Invalid ulimit argument: %s", val);
ret = -1;
goto out;
}
ret = check_default_ulimit_type(parts[0]);
if (ret != 0) {
ret = -1;
goto out;
}
if (parts[1][0] == ':' || parts[1][strlen(parts[1]) - 1] == ':') {
COMMAND_ERROR("Invalid ulimit value: \"%s\", delimiter ':' can't be the first"
" or the last character", val);
ret = -1;
goto out;
}
// parse value
get_default_ulimit_split_parts(parts[1], &limitvals, &limitvals_len, ':');
if (limitvals == NULL) {
ret = -1;
goto out;
}
if (limitvals_len > 2) {
COMMAND_ERROR("Too many limit value arguments - %s, can only have up to two, `soft[:hard]`",
parts[1]);
ret = -1;
goto out;
}
ret = parse_soft_hard_default_ulimit(val, limitvals, limitvals_len, &soft, &hard);
if (ret < 0) {
goto out;
}
ulimit = util_common_calloc_s(sizeof(host_config_ulimits_element));
if (ulimit == NULL) {
ret = -1;
goto out;
}
ulimit->name = util_strdup_s(parts[0]);
ulimit->hard = hard;
ulimit->soft = soft;
out:
util_free_array(parts);
util_free_array(limitvals);
if (ret != 0) {
free_host_config_ulimits_element(ulimit);
ulimit = NULL;
}
return ulimit;
}
int command_default_ulimit_append(command_option_t *option, const char *arg)
{
int ret = 0;
size_t ulimit_len;
host_config_ulimits_element *tmp = NULL;
host_config_ulimits_element **pos = NULL;
if (option == NULL) {
ret = -1;
goto out;
}
tmp = parse_default_ulimit(arg);
if (tmp == NULL) {
ERROR("parse default ulimit from arg failed");
ret = -1;
goto out;
}
for (pos = *(host_config_ulimits_element ***)(option->data); pos != NULL && *pos != NULL; pos++) {
if (strcmp((*pos)->name, tmp->name) == 0) {
break;
}
}
if (pos != NULL && *pos != NULL) {
(*pos)->hard = tmp->hard;
(*pos)->soft = tmp->soft;
goto out;
}
ulimit_len = ulimit_array_len(*(host_config_ulimits_element ***)(option->data));
if (ulimit_array_append(option->data, tmp, ulimit_len) != 0) {
ERROR("default ulimit append failed");
ret = -1;
}
out:
free_host_config_ulimits_element(tmp);
return ret;
}
int command_append_array(command_option_t *option, const char *arg)
{
if (option == NULL) {
return -1;
}
char ***array = option->data;
return util_array_append(array, arg);
}
int command_convert_u16(command_option_t *option, const char *arg)
{
int ret = 0;
if (option == NULL) {
return -1;
}
ret = util_safe_u16(arg, option->data);
if (ret != 0) {
COMMAND_ERROR("Invalid value \"%s\" for flag --%s: %s", arg, option->large, strerror(-ret));
return EINVALIDARGS;
}
return 0;
}
int command_convert_llong(command_option_t *opt, const char *arg)
{
int ret;
if (opt == NULL) {
return -1;
}
ret = util_safe_llong(arg, opt->data);
if (ret != 0) {
COMMAND_ERROR("Invalid value \"%s\" for flag --%s: %s", arg, opt->large, strerror(-ret));
return EINVALIDARGS;
}
return 0;
}
int command_convert_uint(command_option_t *opt, const char *arg)
{
int ret;
if (opt == NULL) {
return -1;
}
ret = util_safe_uint(arg, opt->data);
if (ret != 0) {
COMMAND_ERROR("Invalid value \"%s\" for flag --%s: %s", arg, opt->large, strerror(-ret));
return EINVALIDARGS;
}
return 0;
}
int command_convert_int(command_option_t *option, const char *arg)
{
int ret = 0;
if (option == NULL) {
return -1;
}
ret = util_safe_int(arg, option->data);
if (ret != 0) {
COMMAND_ERROR("Invalid value \"%s\" for flag --%s: %s", arg, option->large, strerror(-ret));
return EINVALIDARGS;
}
return 0;
}
int command_convert_nanoseconds(command_option_t *option, const char *arg)
{
if (option == NULL) {
return -1;
}
if (util_parse_time_str_to_nanoseconds(arg, option->data)) {
COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large);
return EINVALIDARGS;
}
return 0;
}
int command_convert_membytes(command_option_t *option, const char *arg)
{
if (option == NULL) {
return -1;
}
if (util_parse_byte_size_string(arg, option->data) || (*(int64_t *)(option->data)) < 0) {
COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large);
return EINVALIDARGS;
}
return 0;
}
int command_convert_memswapbytes(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 (command_convert_membytes(option, arg)) {
return EINVALIDARGS;
}
return 0;
}
size_t ulimit_array_len(host_config_ulimits_element **default_ulimit)
{
size_t len = 0;
host_config_ulimits_element **pos = NULL;
for (pos = default_ulimit; pos != NULL && *pos != NULL; pos++) {
len++;
}
return len;
}
int ulimit_array_append(host_config_ulimits_element ***ulimit_array, const host_config_ulimits_element *element,
const size_t len)
{
int ret;
size_t old_size, new_size;
host_config_ulimits_element *new_element = NULL;
host_config_ulimits_element **new_ulimit_array = NULL;
if (ulimit_array == NULL || element == NULL) {
return -1;
}
// let new len to len + 2 for element and null
if (len > SIZE_MAX / sizeof(host_config_ulimits_element *) - 2) {
ERROR("Too many ulimit elements!");
return -1;
}
new_size = (len + 2) * sizeof(host_config_ulimits_element *);
old_size = len * sizeof(host_config_ulimits_element *);
ret = mem_realloc((void **)(&new_ulimit_array), new_size, (void *)*ulimit_array, old_size);
if (ret != 0) {
ERROR("Failed to realloc memory for append ulimit");
return -1;
}
*ulimit_array = new_ulimit_array;
new_element = util_common_calloc_s(sizeof(host_config_ulimits_element));
if (new_element == NULL) {
ERROR("Out of memory");
free_default_ulimit(*ulimit_array);
*ulimit_array = NULL;
return -1;
}
new_element->name = util_strdup_s(element->name);
new_element->hard = element->hard;
new_element->soft = element->soft;
new_ulimit_array[len] = new_element;
return 0;
}
void free_default_ulimit(host_config_ulimits_element **default_ulimit)
{
host_config_ulimits_element **p = NULL;
for (p = default_ulimit; p != NULL && *p != NULL; p++) {
free_host_config_ulimits_element(*p);
}
free(default_ulimit);
}

115
src/cmd/commander.h Normal file
View File

@ -0,0 +1,115 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: tanyifeng
* Create: 2017-11-22
* Description: provide command definition
******************************************************************************/
#ifndef __COMMANDER_H_
#define __COMMANDER_H_
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include "host_config.h"
#ifndef COMMANDER_MAX_OPTIONS
#define COMMANDER_MAX_OPTIONS 64
#endif
typedef enum {
/* no arguments */
CMD_OPT_TYPE_BOOL,
CMD_OPT_TYPE_BOOL_FALSE,
/* required arguments */
CMD_OPT_TYPE_STRING,
CMD_OPT_TYPE_STRING_DUP,
CMD_OPT_TYPE_CALLBACK
} command_option_type_t;
struct _command;
struct command_option;
typedef int(*command_callback_t)(struct command_option *options, const char *arg);
typedef struct command_option {
command_option_type_t type;
bool hasdata;
const char *large;
int small;
void *data;
const char *description;
command_callback_t cb;
} command_option_t;
typedef struct _command {
const char *type;
const char *usage;
const char *description;
const char *name;
const char *version;
int option_count;
command_option_t *options;
int argc;
const char **argv;
} command_t;
int command_valid_socket(command_option_t *option, const char *arg);
void command_init(command_t *self, command_option_t *opts, int opts_len, int argc, const char **argv,
const char *description, const char *usage);
int compare_options(const void *s1, const void *s2);
void print_options(int options_len, const command_option_t *options);
void command_help(command_t *self);
void command_option(command_t *self, command_option_type_t type, void *data,
int small, const char *large, const char *desc, command_callback_t cb);
int command_parse_args(command_t *self, int *argc, char * const **argv);
int have_short_options(command_t *self, char arg);
int command_valid_socket_append_array(command_option_t *option, const char *arg);
int command_append_array(command_option_t *option, const char *arg);
int command_convert_u16(command_option_t *option, const char *arg);
int command_convert_llong(command_option_t *opt, const char *arg);
int command_convert_uint(command_option_t *opt, const char *arg);
int command_convert_int(command_option_t *option, const char *arg);
int command_convert_nanoseconds(command_option_t *option, const char *arg);
int command_convert_membytes(command_option_t *option, const char *arg);
int command_convert_memswapbytes(command_option_t *option, const char *arg);
int command_default_ulimit_append(command_option_t *option, const char *arg);
size_t ulimit_array_len(host_config_ulimits_element **default_ulimit);
int ulimit_array_append(host_config_ulimits_element ***default_ulimit,
const host_config_ulimits_element *element,
const size_t len);
int check_default_ulimit_type(const char *type);
void free_default_ulimit(host_config_ulimits_element **default_ulimit);
#endif /* COMMANDER_H */

View File

@ -0,0 +1,27 @@
# get current directory sources files
add_subdirectory(base)
add_subdirectory(information)
add_subdirectory(extend)
add_subdirectory(stream)
add_subdirectory(images)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} lcrc_srcs)
set(CMD_LCRC_SRCS
${lcrc_srcs}
${LCRC_BASE_SRCS}
${LCRC_EXTEND_SRCS}
${LCRC_IMAGES_SRCS}
${LCRC_INFORMATION_SRCS}
${LCRC_STREAM_SRCS}
PARENT_SCOPE
)
set(CMD_LCRC_INCS
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/base
${CMAKE_CURRENT_SOURCE_DIR}/extend
${CMAKE_CURRENT_SOURCE_DIR}/images
${CMAKE_CURRENT_SOURCE_DIR}/information
${CMAKE_CURRENT_SOURCE_DIR}/stream
PARENT_SCOPE
)

272
src/cmd/lcrc/arguments.c Normal file
View File

@ -0,0 +1,272 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: maoweiyong
* Create: 2017-11-22
* Description: provide container client arguments functions
******************************************************************************/
#include "arguments.h"
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include "error.h"
#include "commander.h"
#include "log.h"
#include "securec.h"
#include "utils.h"
#include "constants.h"
client_connect_config_t get_connect_config(const struct client_arguments *args)
{
client_connect_config_t config = { 0 };
config.socket = args->socket;
// unix socket not support tls
if (strncmp(args->socket, "tcp://", strlen("tcp://"))) {
config.tls_verify = false;
config.tls = false;
config.ca_file = NULL;
config.cert_file = NULL;
config.key_file = NULL;
} else {
config.tls = args->tls;
config.tls_verify = args->tls_verify;
if (args->tls_verify) {
config.tls = true;
}
config.ca_file = args->ca_file;
config.cert_file = args->cert_file;
config.key_file = args->key_file;
}
return config;
}
static int set_default_tls_options(struct client_arguments *args)
{
int ret = -1;
char *tls = NULL;
char *tls_verify = NULL;
char *tmp_path = NULL;
char *cert_path = NULL;
char *ca_file = NULL;
char *cert_file = NULL;
char *key_file = NULL;
tls = getenv("ISULAD_TLS");
args->tls = (tls != NULL && strlen(tls) != 0 && strcmp(tls, "0") != 0);
tls = NULL;
tls_verify = getenv("ISULAD_TLS_VERIFY");
args->tls_verify = (tls_verify != NULL && strlen(tls_verify) != 0 && strcmp(tls_verify, "0") != 0);
tls_verify = NULL;
tmp_path = getenv("ISULAD_CERT_PATH");
if (tmp_path != NULL && strlen(tmp_path) != 0) {
cert_path = util_strdup_s(tmp_path);
ca_file = util_path_join(cert_path, DEFAULT_CA_FILE);
if (ca_file == NULL) {
goto out;
}
free(args->ca_file);
args->ca_file = ca_file;
key_file = util_path_join(cert_path, DEFAULT_KEY_FILE);
if (key_file == NULL) {
goto out;
}
free(args->key_file);
args->key_file = key_file;
cert_file = util_path_join(cert_path, DEFAULT_CERT_FILE);
if (cert_file == NULL) {
goto out;
}
free(args->cert_file);
args->cert_file = cert_file;
}
ret = 0;
out:
free(cert_path);
return ret;
}
/* client arguments init */
int client_arguments_init(struct client_arguments *args)
{
char *host = NULL;
if (args == NULL) {
return -1;
}
args->name = NULL;
args->create_rootfs = NULL;
args->log_file = "none";
args->argc = 0;
args->argv = NULL;
host = getenv("ISULAD_HOST");
if (host != NULL && strlen(host) != 0) {
args->socket = util_strdup_s(host);
} else {
args->socket = util_strdup_s(DEFAULT_UNIX_SOCKET);
}
if (memset_s(&args->custom_conf, sizeof(args->custom_conf), 0x00, sizeof(struct custom_configs)) != EOK) {
COMMAND_ERROR("Failed to set memory");
return -1;
}
if (memset_s(&args->cr, sizeof(args->cr), 0x00, sizeof(struct args_cgroup_resources)) != EOK) {
COMMAND_ERROR("Failed to set memory");
return -1;
}
if (set_default_tls_options(args) != 0) {
return -1;
}
return 0;
}
/* client arguments free */
void client_arguments_free(struct client_arguments *args)
{
int i;
struct custom_configs *custom_conf = NULL;
if (args == NULL) {
return;
}
free(args->name);
args->name = NULL;
free(args->socket);
args->socket = NULL;
util_free_array(args->filters);
args->filters = NULL;
custom_conf = &(args->custom_conf);
if (custom_conf == NULL) {
return;
}
util_free_array(custom_conf->env);
custom_conf->env = NULL;
util_free_array(custom_conf->hugepage_limits);
custom_conf->hugepage_limits = NULL;
free(custom_conf->hook_spec);
custom_conf->hook_spec = NULL;
free(custom_conf->env_target_file);
custom_conf->env_target_file = NULL;
free(custom_conf->cgroup_parent);
custom_conf->cgroup_parent = NULL;
free(custom_conf->user);
custom_conf->user = NULL;
free(custom_conf->hostname);
custom_conf->hostname = NULL;
util_free_array(custom_conf->cap_adds);
custom_conf->cap_adds = NULL;
util_free_array(custom_conf->cap_drops);
custom_conf->cap_drops = NULL;
util_free_array(custom_conf->storage_opts);
custom_conf->storage_opts = NULL;
util_free_array(custom_conf->sysctls);
custom_conf->sysctls = NULL;
util_free_array(custom_conf->volumes);
custom_conf->volumes = NULL;
free(custom_conf->entrypoint);
custom_conf->entrypoint = NULL;
util_free_array(custom_conf->ulimits);
custom_conf->ulimits = NULL;
util_free_array(custom_conf->devices);
custom_conf->devices = NULL;
util_free_array(custom_conf->weight_devices);
custom_conf->weight_devices = NULL;
for (i = 0; i < NAMESPACE_MAX; i++) {
free(custom_conf->share_ns[i]);
custom_conf->share_ns[i] = NULL;
}
free(args->create_rootfs);
args->create_rootfs = NULL;
free_json_map_string_string(args->annotations);
args->annotations = NULL;
free(custom_conf->workdir);
custom_conf->workdir = NULL;
util_free_array(custom_conf->security);
custom_conf->security = NULL;
free(args->ca_file);
args->ca_file = NULL;
free(args->cert_file);
args->cert_file = NULL;
free(args->key_file);
args->key_file = NULL;
}
/* print common help */
void print_common_help()
{
struct client_arguments cmd_common_args = {};
struct command_option options[] = { COMMON_OPTIONS(cmd_common_args), VERSION_OPTIONS(cmd_common_args) };
size_t len = sizeof(options) / sizeof(options[0]);
qsort(options, len, sizeof(options[0]), compare_options);
fprintf(stdout, "COMMON OPTIONS :\n");
print_options((int)len, options);
}
/* client print error */
void client_print_error(uint32_t cc, uint32_t server_errono, const char *errmsg)
{
switch (server_errono) {
case LCRD_SUCCESS:
if (errmsg != NULL) {
COMMAND_ERROR("%s", errmsg);
}
break;
default:
if (errmsg != NULL) {
COMMAND_ERROR("Error response from daemon: %s", errmsg);
} else {
COMMAND_ERROR("%s", errno_to_error_message(server_errono));
}
break;
}
}

346
src/cmd/lcrc/arguments.h Normal file
View File

@ -0,0 +1,346 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: lifeng
* Create: 2017-11-22
* Description: provide container client arguments definition
******************************************************************************/
#ifndef __LCRC_ARGUMENTS_H
#define __LCRC_ARGUMENTS_H
#include <stdbool.h>
#include <getopt.h>
#include <stdio.h>
#include <stdint.h>
#include "commander.h"
#include "container_def.h"
#include "json_common.h"
#include "lcrc_connect.h"
/* max arguments can be specify in client */
#define MAX_CLIENT_ARGS 1000
struct client_arguments;
struct custom_configs;
struct custom_configs {
/* environment variables */
char **env;
/* hugepage limits */
char **hugepage_limits;
/* group add*/
char **group_add;
/* hook-spec file */
char *hook_spec;
/* volumes to mount */
char **volumes;
/* mounts to attach a filesystem */
char **mounts;
/* pids limit */
int64_t pids_limit;
/* files limit */
int64_t files_limit;
/* shm size */
int64_t shm_size;
/* user and group */
char *user;
/* hostname */
char *hostname;
/* privileged */
bool privileged;
/* auto remove */
bool auto_remove;
/* readonly rootfs */
bool readonly;
/* alldevices */
bool all_devices;
/* system container */
bool system_container;
char *ns_change_opt;
/* user remap */
char *user_remap;
/* cap add */
char **cap_adds;
/* cap drop */
char **cap_drops;
/* storage opts */
char **storage_opts;
/* sysctls */
char **sysctls;
/* extra hosts */
char **extra_hosts;
/* dns */
char **dns;
/* dns options */
char **dns_options;
/* dns search */
char **dns_search;
/* tty */
bool tty;
/* open stdin of container */
bool open_stdin;
/* attach stdin of container */
bool attach_stdin;
/* attach stdout of container */
bool attach_stdout;
/* attach stderr of container */
bool attach_stderr;
/* entrypoint */
char *entrypoint;
/* populate devices */
char **devices;
/* ulimit options */
char **ulimits;
/* blkio weight devices */
char **weight_devices;
/* namespace mode */
char *share_ns[NAMESPACE_MAX];
/* work dir */
char *workdir;
/* security opt */
char **security;
/* health cmd */
char *health_cmd;
/* health interval */
int64_t health_interval;
/* health retries */
int health_retries;
/* health timeout */
int64_t health_timeout;
/* health start period */
int64_t health_start_period;
/* no healthcheck */
bool no_healthcheck;
/* exit on unhealthy */
bool exit_on_unhealthy;
/* oom kill disable */
bool oom_kill_disable;
/* create/run accel options */
char **accel;
/* env target file */
char *env_target_file;
/* cgroup parent */
char *cgroup_parent;
/* device read bps */
char **blkio_throttle_read_bps_device;
/* device write bps */
char **blkio_throttle_write_bps_device;
};
struct args_cgroup_resources {
uint16_t blkio_weight;
int64_t cpu_shares;
int64_t cpu_period;
int64_t cpu_quota;
int64_t cpu_rt_period;
int64_t cpu_rt_runtime;
int64_t oom_score_adj;
char *cpuset_cpus;
char *cpuset_mems;
int64_t memory_limit;
int64_t memory_swap;
int64_t memory_reservation;
int64_t kernel_memory_limit;
};
struct client_arguments {
const char *progname; /* main progname name */
const char *subcommand; /* sub command name */
const struct option *options;
// For common options
char *name; /* container name */
char *socket;
char *runtime;
char *restart;
char *host_channel;
// lcr create
char *external_rootfs;
char *create_rootfs;
char *image_name;
char *log_file;
char *log_file_size;
unsigned int log_file_rotate;
/* notes: we should free the mem in custom_conf by hand*/
struct custom_configs custom_conf;
// lcrc run;
bool detach;
bool interactive;
// stop/kill/delete
bool force;
int time;
// delete
bool volume;
// events
char *since;
char *until;
// health check
char *service;
// list
bool dispname;
bool list_all;
char **filters;
// inspect
char *format;
// stats
bool nostream;
bool showall;
// update
struct args_cgroup_resources cr;
// pull/rmi
char *ref;
bool plain_http;
// logs
bool follow;
/*
* tail < 0: show all logs
* tail = 0: do not show log
* tail > 0: show number of logs set by tail
* */
long long tail;
// kill
char *signal;
// load
char *file;
char *type;
char *tag;
// login/logout
char *username;
char *password;
char *server;
bool password_stdin;
/* extra environment variables used in exec */
char **extra_env;
// remaining arguments
char * const *argv;
int argc;
// top
char *ps_args;
json_map_string_string *annotations;
// gRPC tls config
bool tls;
bool tls_verify;
char *ca_file;
char *cert_file;
char *key_file;
};
#define LOG_OPTIONS(log) \
{ CMD_OPT_TYPE_BOOL_FALSE, false, "debug", 'D', &(log).quiet, "Enable debug mode", NULL }
#define COMMON_OPTIONS(cmdargs) \
{ 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}, \
{ CMD_OPT_TYPE_BOOL, false, "tlsverify", 0, &(cmdargs).tls_verify, \
"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 }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "tlscert", 0, &(cmdargs).cert_file, \
"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 }, \
{ CMD_OPT_TYPE_STRING, false, "help", 0, NULL, "Print usage", NULL }
#define VERSION_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_BOOL, false, "version", 0, NULL, "Print version information and quit", NULL }
extern void print_common_help();
extern int client_arguments_init(struct client_arguments *args);
extern void client_arguments_free(struct client_arguments *args);
extern void lcrd_screen_print(uint32_t cc, uint32_t server_errono,
struct client_arguments *args);
extern void client_print_error(uint32_t cc, uint32_t server_errono, const char *errmsg);
extern client_connect_config_t get_connect_config(const struct client_arguments *args);
#endif /*__LCRC_ARGUMENTS_H*/

View File

@ -0,0 +1,7 @@
# get current directory sources files
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} lcrc_base_srcs)
set(LCRC_BASE_SRCS
${lcrc_base_srcs}
PARENT_SCOPE
)

2023
src/cmd/lcrc/base/create.c Normal file

File diff suppressed because it is too large Load Diff

170
src/cmd/lcrc/base/create.h Normal file
View File

@ -0,0 +1,170 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: lifeng
* Create: 2017-11-22
* Description: provide container create definition
******************************************************************************/
#ifndef __CMD_CREATE_H
#define __CMD_CREATE_H
#include "arguments.h"
#define CREATE_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_CALLBACK, false, "accel", 0, &(cmdargs).custom_conf.accel, \
"Accelerator bindings (format: [<name>=]<runtime>[@<driver>[,<options>]])", \
command_append_array }, \
{ CMD_OPT_TYPE_BOOL, false, "read-only", 0, &(cmdargs).custom_conf.readonly, \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "cap-drop", 0, &(cmdargs).custom_conf.cap_drops, \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "cpu-period", 0, &(cmdargs).cr.cpu_period, \
"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 }, \
{ 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 }, \
{ CMD_OPT_TYPE_STRING, false, "cpuset-mems", 0, &(cmdargs).cr.cpuset_mems, \
"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 }, \
{ 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 }, \
{ 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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "device", 0, &(cmdargs).custom_conf.devices, \
"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 }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "entrypoint", 0, &(cmdargs).custom_conf.entrypoint, \
"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 LCRD 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 }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "hook-spec", 0, &(cmdargs).custom_conf.hook_spec, \
"File containing hook definition(prestart, poststart, poststop)", NULL }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "hostname", 'h', &(cmdargs).custom_conf.hostname, \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "dns", 0, &(cmdargs).custom_conf.dns, \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "dns-search", 0, &(cmdargs).custom_conf.dns_search, \
"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 }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "ipc", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_IPC], \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "kernel-memory", 0, &(cmdargs).cr.kernel_memory_limit, \
"Kernel memory limit", command_convert_membytes }, \
{ CMD_OPT_TYPE_CALLBACK, false, "hugetlb-limit", 0, &(cmdargs).custom_conf.hugepage_limits, \
"Huge page limit (format: [size:]<limit>, 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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "memory", 'm', &(cmdargs).cr.memory_limit, \
"Memory limit", command_convert_membytes }, \
{ CMD_OPT_TYPE_CALLBACK, false, "memory-reservation", 0, &(cmdargs).cr.memory_reservation, \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "mount", 0, &(cmdargs).custom_conf.mounts, \
"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 }, \
{ 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 }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "pid", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_PID], \
"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 }, \
{ CMD_OPT_TYPE_BOOL, false, "privileged", 0, &(cmdargs).custom_conf.privileged, \
"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 }, \
{ CMD_OPT_TYPE_STRING, false, "host-channel", 0, &(cmdargs).host_channel, \
"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 }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "user", 'u', &(cmdargs).custom_conf.user, \
"Username or UID (format: <name|uid>[:<group|gid>])", NULL }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "uts", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_UTS], \
"UTS namespace to use", NULL }, \
{ CMD_OPT_TYPE_CALLBACK, false, "volume", 'v', &(cmdargs).custom_conf.volumes, \
"Bind mount a volume", command_append_array }, \
{ CMD_OPT_TYPE_CALLBACK, false, "annotation", 0, &(cmdargs), \
"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 }, \
{ CMD_OPT_TYPE_BOOL, false, "system-container", 0, &(cmdargs).custom_conf.system_container, \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "security-opt", 0, &(cmdargs).custom_conf.security, \
"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 }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "health-cmd", 0, &(cmdargs).custom_conf.health_cmd, \
"Command to run to check health", NULL }, \
{ CMD_OPT_TYPE_CALLBACK, false, "sysctl", 0, &(cmdargs).custom_conf.sysctls, \
"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 }, \
{ CMD_OPT_TYPE_STRING_DUP, false, "cgroup-parent", 0, &(cmdargs).custom_conf.cgroup_parent, \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "health-retries", 0, &(cmdargs).custom_conf.health_retries, \
"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 }, \
{ 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 }, \
{ CMD_OPT_TYPE_BOOL, false, "no-healthcheck", 0, &(cmdargs).custom_conf.no_healthcheck, \
"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 }, \
{ CMD_OPT_TYPE_STRING, false, "ns-change-opt", 0, &(cmdargs).custom_conf.ns_change_opt, \
"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 }
#define CREATE_EXTEND_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_BOOL, false, "interactive", 'i', &(cmdargs).custom_conf.open_stdin, \
"Keep STDIN open even if not attached", NULL }
extern const char g_cmd_create_desc[];
extern const char g_cmd_create_usage[];
extern struct client_arguments g_cmd_create_args;
int create_parser(struct client_arguments *args, int c, char *arg);
int create_checker(struct client_arguments *args);
int client_create(struct client_arguments *args);
int callback_log_opt(command_option_t *option, const char *value);
int callback_annotation(command_option_t *option, const char *value);
int cmd_create_main(int argc, const char **argv);
#endif /* __CMD_CREATE_H */

139
src/cmd/lcrc/base/kill.c Normal file
View File

@ -0,0 +1,139 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container kill functions
******************************************************************************/
#include "error.h"
#include "securec.h"
#include "arguments.h"
#include "kill.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_kill_desc[] = "Kill one or more running containers";
const char g_cmd_kill_usage[] = "kill [OPTIONS] CONTAINER [CONTAINER...]";
struct client_arguments g_cmd_kill_args = {
.signal = "SIGKILL",
};
static int client_kill(const struct client_arguments *args)
{
int ret = 0;
int signal = -1;
lcrc_connect_ops *ops = NULL;
struct lcrc_kill_request request = { 0 };
struct lcrc_kill_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(struct lcrc_kill_response));
if (response == NULL) {
ERROR("Kill: Out of memory");
return -1;
}
request.name = args->name;
signal = util_sig_parse(args->signal);
if (signal < 0) {
ERROR("Invalid signal number");
ret = -1;
goto out;
}
request.signal = (uint32_t)signal;
ops = get_connect_client_ops();
if (ops == NULL || ops->container.kill == NULL) {
ERROR("Unimplemented kill op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.kill(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
goto out;
}
out:
lcrc_kill_response_free(response);
return ret;
}
int cmd_kill_main(int argc, const char **argv)
{
int signo;
int i = 0;
int status = 0;
command_t cmd;
struct log_config lconf = { 0 };
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_kill_args)) {
COMMAND_ERROR("client arguments init failed\n");
exit(ECOMMON);
}
g_cmd_kill_args.progname = argv[0];
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_kill_args),
KILL_OPTIONS(g_cmd_kill_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_kill_desc,
g_cmd_kill_usage);
if (command_parse_args(&cmd, &g_cmd_kill_args.argc, &g_cmd_kill_args.argv)) {
exit(ECOMMON);
}
if (log_init(&lconf)) {
COMMAND_ERROR("log init failed\n");
exit(ECOMMON);
}
signo = util_sig_parse(g_cmd_kill_args.signal);
if (signo == -1) {
COMMAND_ERROR("Invalid signal: %s", g_cmd_kill_args.signal);
exit(ECOMMON);
}
if (!util_valid_signal(signo)) {
COMMAND_ERROR("The Linux daemon does not support signal %d", signo);
exit(ECOMMON);
}
if (g_cmd_kill_args.argc == 0) {
COMMAND_ERROR("Kill requires at least 1 container names");
exit(EINVALIDARGS);
}
if (g_cmd_kill_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to kill.");
exit(EINVALIDARGS);
}
for (i = 0; i < g_cmd_kill_args.argc; i++) {
g_cmd_kill_args.name = g_cmd_kill_args.argv[i];
if (client_kill(&g_cmd_kill_args)) {
ERROR("Container \"%s\" kill failed", g_cmd_kill_args.name);
status = -1;
continue;
}
printf("%s\n", g_cmd_kill_args.name);
}
if (status) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

29
src/cmd/lcrc/base/kill.h Normal file
View File

@ -0,0 +1,29 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container kill definition
******************************************************************************/
#ifndef __CMD_KILL_H
#define __CMD_KILL_H
#include "arguments.h"
#include "wait.h"
#define KILL_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_STRING, false, "signal", 's', &(cmdargs).signal, \
"Signal to send to the container (default \"SIGKILL\")", NULL }
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);
#endif

View File

@ -0,0 +1,98 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container stop functions
******************************************************************************/
#include "rename.h"
#include "securec.h"
#include "arguments.h"
#include "log.h"
#include "utils.h"
#include "lcrc_connect.h"
const char g_cmd_rename_desc[] = "Rename a container";
const char g_cmd_rename_usage[] =
"rename [OPTIONS] OLD_NAME NEW_NAME";
struct client_arguments g_cmd_rename_args = { 0 };
static int client_rename(const struct client_arguments *args)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
struct lcrc_rename_request request = { 0 };
struct lcrc_rename_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(*response));
if (response == NULL) {
ERROR("Stop: Out of memory");
return -1;
}
request.old_name = args->argv[0];
request.new_name = args->argv[1];
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.rename) {
ERROR("Unimplemented stop op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.rename(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
out:
lcrc_rename_response_free(response);
return ret;
}
int cmd_rename_main(int argc, const char **argv)
{
struct log_config lconf = {0};
command_t cmd;
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_rename_args)
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_rename_args)) {
COMMAND_ERROR("client arguments init failed\n");
exit(ECOMMON);
}
g_cmd_rename_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]),
argc,
(const char **)argv, g_cmd_rename_desc, g_cmd_rename_usage);
if (command_parse_args(&cmd, &g_cmd_rename_args.argc, &g_cmd_rename_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("log init failed\n");
exit(ECOMMON);
}
if (g_cmd_rename_args.argc != 2) {
COMMAND_ERROR("\"rename\" requires 2 arguments.");
exit(ECOMMON);
}
if (client_rename(&g_cmd_rename_args)) {
ERROR("Container \"%s\" rename failed", g_cmd_rename_args.argv[0]);
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container rename definition
******************************************************************************/
#ifndef __CMD_RENAME_H
#define __CMD_RENAME_H
#include "arguments.h"
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);
#endif

119
src/cmd/lcrc/base/restart.c Normal file
View File

@ -0,0 +1,119 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container restart functions
******************************************************************************/
#include <unistd.h>
#include <securec.h>
#include "restart.h"
#include "arguments.h"
#include "log.h"
#include "utils.h"
#include "lcrc_connect.h"
const char g_cmd_restart_desc[] = "Restart one or more containers";
const char g_cmd_restart_usage[] = "restart [OPTIONS] CONTAINER [CONTAINER...]";
struct client_arguments g_cmd_restart_args = {
.force = false,
.time = 10,
};
static int client_restart(const struct client_arguments *args)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
struct lcrc_restart_request request = { 0 };
struct lcrc_restart_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(struct lcrc_restart_response));
if (response == NULL) {
ERROR("Out of memory");
return -1;
}
request.name = args->name;
request.timeout = (unsigned int)args->time;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.restart) {
ERROR("Unimplemented ops");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.restart(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
out:
lcrc_restart_response_free(response);
return ret;
}
int cmd_restart_main(int argc, const char **argv)
{
int i = 0;
int status = 0;
command_t cmd;
struct log_config lconf = { 0 };
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_restart_args),
RESTART_OPTIONS(g_cmd_restart_args)
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_restart_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_restart_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_restart_desc,
g_cmd_restart_usage);
if (command_parse_args(&cmd, &g_cmd_restart_args.argc, &g_cmd_restart_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Restart: log init failed");
exit(ECOMMON);
}
if (g_cmd_restart_args.argc == 0) {
COMMAND_ERROR("Restart requires at least 1 container names");
exit(EINVALIDARGS);
}
if (g_cmd_restart_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to restart.");
exit(EINVALIDARGS);
}
for (i = 0; i < g_cmd_restart_args.argc; i++) {
g_cmd_restart_args.name = g_cmd_restart_args.argv[i];
if (client_restart(&g_cmd_restart_args)) {
status = -1;
continue;
}
printf("%s\n", g_cmd_restart_args.name);
}
if (status != 0) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,27 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container restart definition
******************************************************************************/
#ifndef __CMD_RESTART_H
#define __CMD_RESTART_H
#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 }
extern const char g_cmd_restart_desc[];
extern const char g_cmd_restart_usage[];
extern struct client_arguments g_cmd_restart_args;
int cmd_restart_main(int argc, const char **argv);
#endif /* __CMD_RESTART_H */

158
src/cmd/lcrc/base/rm.c Normal file
View File

@ -0,0 +1,158 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container remove functions
******************************************************************************/
#include <limits.h>
#include "rm.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
#include "commands.h"
#include "console.h"
#include "utils.h"
#include "securec.h"
const char g_cmd_delete_desc[] = "Remove one or more containers";
const char g_cmd_delete_usage[] = "rm [OPTIONS] CONTAINER [CONTAINER...]";
struct client_arguments g_cmd_delete_args = {
.force = false,
.volume = false,
};
/*
* Create a rm request message and call RPC
*/
static int client_delete(const struct client_arguments *args)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
struct lcrc_delete_request request = { 0 };
struct lcrc_delete_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(struct lcrc_delete_response));
if (response == NULL) {
ERROR("RM: Out of memory");
return -1;
}
request.name = args->name;
request.force = args->force;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.remove) {
ERROR("Unimplemented rm op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.remove(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
if (response->name != NULL) {
g_cmd_delete_args.name = util_strdup_s(response->name);
}
out:
lcrc_delete_response_free(response);
return ret;
}
static void do_delete_console_fifo(const char *name, const char *stdflag)
{
int ret = 0;
char fifo_dir[PATH_MAX] = { 0 };
char fifo_name[PATH_MAX] = { 0 };
ret = console_fifo_name(CLIENT_RUNDIR, name, stdflag, fifo_name, sizeof(fifo_name), fifo_dir,
sizeof(fifo_dir), false);
if (ret != 0) {
ERROR("Failed to get console fifo name.");
goto out;
}
console_fifo_delete(fifo_name);
if (util_recursive_rmdir(fifo_dir, 0)) {
ERROR("Failed to delete FIFO path:%s", fifo_dir);
}
out:
return;
}
static void delete_console_fifo(const char *name)
{
do_delete_console_fifo(name, "in");
do_delete_console_fifo(name, "out");
do_delete_console_fifo(name, "err");
return;
}
int cmd_delete_main(int argc, const char **argv)
{
int i = 0;
bool status = false;
struct log_config lconf = { 0 };
command_t cmd;
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_delete_args),
DELETE_OPTIONS(g_cmd_delete_args)
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_delete_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_delete_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_delete_desc,
g_cmd_delete_usage);
if (command_parse_args(&cmd, &g_cmd_delete_args.argc, &g_cmd_delete_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Rm: log init failed");
exit(ECOMMON);
}
if (g_cmd_delete_args.argc == 0) {
COMMAND_ERROR("\"%s rm\" requires at least 1 argument(s).", g_cmd_delete_args.progname);
COMMAND_ERROR("See '%s rm --help'.", g_cmd_delete_args.progname);
exit(ECOMMON);
}
if (g_cmd_delete_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to remove.");
exit(ECOMMON);
}
for (i = 0; i < g_cmd_delete_args.argc; i++) {
g_cmd_delete_args.name = g_cmd_delete_args.argv[i];
if (client_delete(&g_cmd_delete_args)) {
ERROR("Container \"%s\" rm failed", g_cmd_delete_args.name);
status = true;
continue;
}
delete_console_fifo(g_cmd_delete_args.name);
printf("%s\n", g_cmd_delete_args.name);
}
if (status) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

31
src/cmd/lcrc/base/rm.h Normal file
View File

@ -0,0 +1,31 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container remove definition
******************************************************************************/
#ifndef __CMD_DELETE_H
#define __CMD_DELETE_H
#include "arguments.h"
#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 }
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);
#endif /* __CMD_DELETE_H */

219
src/cmd/lcrc/base/run.c Normal file
View File

@ -0,0 +1,219 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container run functions
******************************************************************************/
#include <unistd.h>
#include "run.h"
#include "arguments.h"
#include "log.h"
#include "utils.h"
#include "lcrc_connect.h"
#include "console.h"
#include "error.h"
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",
.restart = "no",
.log_file = NULL,
.log_file_size = "1MB",
.log_file_rotate = 7,
};
static int local_cmd_start(struct client_arguments *args, uint32_t *exit_code)
{
int ret = 0;
bool reset_tty = false;
struct termios oldtios;
struct command_fifo_config *console_fifos = NULL;
ret = client_start(&g_cmd_run_args, &reset_tty, &oldtios, &console_fifos);
if (ret != 0) {
goto free_out;
}
if (!g_cmd_run_args.detach) {
ret = client_wait(&g_cmd_run_args, exit_code);
if (ret != 0) {
goto free_out;
}
ret = (int)(*exit_code);
}
client_wait_fifo_exit(&g_cmd_run_args);
free_out:
client_restore_console(reset_tty, &oldtios, console_fifos);
return ret;
}
static int remote_cmd_start_set_tty(const struct client_arguments *args, bool *reset_tty, struct termios *oldtios)
{
int istty = 0;
istty = isatty(0);
if (istty && args->custom_conf.tty && args->custom_conf.attach_stdin) {
if (setup_tios(0, oldtios)) {
ERROR("Failed to setup terminal properties");
return -1;
}
*reset_tty = true;
}
return 0;
}
static int remote_cmd_start(const struct client_arguments *args, uint32_t *exit_code)
{
int ret = 0;
bool reset_tty = false;
lcrc_connect_ops *ops = NULL;
struct lcrc_start_request request = { 0 };
struct lcrc_start_response *response = NULL;
client_connect_config_t config = { 0 };
struct termios oldtios;
ops = get_connect_client_ops();
if (ops == NULL || ops->container.remote_start == NULL) {
ERROR("Unimplemented ops");
ret = ECOMMON;
goto out;
}
if (remote_cmd_start_set_tty(args, &reset_tty, &oldtios) != 0) {
ret = ECOMMON;
goto out;
}
request.name = args->name;
request.attach_stdin = args->custom_conf.attach_stdin;
request.attach_stdout = args->custom_conf.attach_stdout;
request.attach_stderr = args->custom_conf.attach_stderr;
response = util_common_calloc_s(sizeof(struct lcrc_start_response));
if (response == NULL) {
ERROR("Out of memory");
ret = ECOMMON;
goto out;
}
config = get_connect_config(args);
ret = ops->container.remote_start(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
ret = ECOMMON;
if (response->server_errono ||
(response->errmsg && !strcmp(response->errmsg, errno_to_error_message(LCRD_ERR_CONNECT)))) {
ret = ESERVERERROR;
}
goto out;
}
out:
lcrc_start_response_free(response);
if (reset_tty && tcsetattr(0, TCSAFLUSH, &oldtios) < 0) {
ERROR("Failed to reset terminal properties");
return -1;
}
return ret;
}
int cmd_run_main(int argc, const char **argv)
{
int ret = 0;
unsigned int exit_code = 0;
command_t cmd = { 0 };
struct log_config lconf = { 0 };
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_run_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_run_args.custom_conf.attach_stdout = true;
g_cmd_run_args.custom_conf.attach_stderr = true;
g_cmd_run_args.progname = argv[0];
g_cmd_run_args.subcommand = argv[1];
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_run_args),
CREATE_OPTIONS(g_cmd_run_args),
CREATE_EXTEND_OPTIONS(g_cmd_run_args),
RUN_OPTIONS(g_cmd_run_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_run_desc,
g_cmd_run_usage);
if (command_parse_args(&cmd, &g_cmd_run_args.argc, &g_cmd_run_args.argv) || run_checker(&g_cmd_run_args)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("log init failed");
exit(ECOMMON);
}
ret = client_create(&g_cmd_run_args);
if (ret) {
ERROR("Container \"%s\" create failed", g_cmd_run_args.name);
exit(ret);
}
if (g_cmd_run_args.detach) {
printf("%s\n", g_cmd_run_args.name);
}
if (strncmp(g_cmd_run_args.socket, "tcp://", strlen("tcp://")) == 0) {
ret = remote_cmd_start(&g_cmd_run_args, &exit_code);
if (ret != 0) {
ERROR("Failed to execute command with remote run");
goto free_out;
}
} else {
ret = local_cmd_start(&g_cmd_run_args, &exit_code);
if (ret != 0) {
ERROR("Failed to execute command with local run");
goto free_out;
}
}
free_out:
client_arguments_free(&g_cmd_run_args);
exit(ret);
}
static int run_checker(struct client_arguments *args)
{
int ret = 0;
ret = create_checker(args);
if (ret) {
goto out;
}
/* Make detach option a high priority than terminal*/
if (args->detach) {
args->custom_conf.attach_stdin = false;
args->custom_conf.attach_stdout = false;
args->custom_conf.attach_stderr = false;
}
if (args->custom_conf.auto_remove && ((args->restart != NULL) && (strcmp("no", args->restart) != 0))) {
COMMAND_ERROR("Conflicting options: --restart and --rm");
ret = -1;
goto out;
}
out:
return ret;
}

33
src/cmd/lcrc/base/run.h Normal file
View File

@ -0,0 +1,33 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container run definition
******************************************************************************/
#ifndef __CMD_RUN_H
#define __CMD_RUN_H
#include "create.h"
#include "start.h"
#include "wait.h"
#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 }
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);
#endif /* __CMD_RUN_H */

246
src/cmd/lcrc/base/start.c Normal file
View File

@ -0,0 +1,246 @@
/******************************************************************************
* 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: maoweiyong
* Create: 2018-11-08
* Description: provide container start functions
******************************************************************************/
#include <semaphore.h>
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
#include <malloc.h>
#include "error.h"
#include "securec.h"
#include "arguments.h"
#include "commander.h"
#include "start.h"
#include "log.h"
#include "lcrc_connect.h"
#include "console.h"
#include "utils.h"
#include "commands.h"
const char g_cmd_start_desc[] = "Start one or more stopped containers";
const char g_cmd_start_usage[] = "start [OPTIONS] CONTAINER [CONTAINER...]";
sem_t g_console_waitopen_sem;
sem_t g_console_waitexit_sem;
struct client_arguments g_cmd_start_args = {};
static int start_cmd_init(const struct client_arguments *args)
{
if (sem_init(&g_console_waitopen_sem, 0, 0)) {
ERROR("Container %s Semaphore initialization failed", args->name);
return ECOMMON;
}
if (sem_init(&g_console_waitexit_sem, 0, 0)) {
ERROR("Container %s Semaphore initialization failed", args->name);
sem_destroy(&g_console_waitopen_sem);
return ECOMMON;
}
return 0;
}
static int start_prepare_console(const struct client_arguments *args, struct termios *oldtios, bool *reset_tty,
struct command_fifo_config **console_fifos)
{
int ret = 0;
int istty = 0;
istty = isatty(0);
if (istty && args->custom_conf.tty && args->custom_conf.attach_stdin) {
if (setup_tios(0, oldtios)) {
ERROR("Failed to setup terminal properties");
ret = ECOMMON;
goto out;
}
*reset_tty = true;
}
if (!istty) {
INFO("The input device is not a TTY");
}
if (args->custom_conf.attach_stdin || args->custom_conf.attach_stdout || args->custom_conf.attach_stderr) {
if (create_console_fifos(args->custom_conf.attach_stdin, args->custom_conf.attach_stdout,
args->custom_conf.attach_stderr, args->name, "start", console_fifos)) {
ERROR("Container \"%s\" create console FIFO failed", args->name);
ret = ECOMMON;
goto out;
}
(*console_fifos)->wait_open = &g_console_waitopen_sem;
(*console_fifos)->wait_exit = &g_console_waitexit_sem;
if (start_client_console_thread(*console_fifos, args->custom_conf.tty)) {
ERROR("Container \"%s\" start console thread failed", args->name);
ret = ECOMMON;
goto out;
}
}
out:
return ret;
}
static int do_client_start(const struct client_arguments *args, struct command_fifo_config **console_fifos)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
struct lcrc_start_request request = { 0 };
struct lcrc_start_response *response = NULL;
client_connect_config_t config = { 0 };
ops = get_connect_client_ops();
if (ops == NULL || ops->container.start == NULL) {
ERROR("Unimplemented ops");
ret = ECOMMON;
goto out;
}
request.name = args->name;
if (console_fifos != NULL && *console_fifos != NULL) {
request.stdin = (*console_fifos)->stdin_name;
request.stdout = (*console_fifos)->stdout_name;
request.stderr = (*console_fifos)->stderr_name;
}
request.attach_stdin = args->custom_conf.attach_stdin;
request.attach_stdout = args->custom_conf.attach_stdout;
request.attach_stderr = args->custom_conf.attach_stderr;
response = util_common_calloc_s(sizeof(struct lcrc_start_response));
if (response == NULL) {
ERROR("Out of memory");
ret = ECOMMON;
goto out;
}
config = get_connect_config(args);
ret = ops->container.start(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
if (response->server_errono ||
(response->errmsg && !strcmp(response->errmsg, errno_to_error_message(LCRD_ERR_CONNECT)))) {
ret = ESERVERERROR;
util_contain_errmsg(response->errmsg, &ret);
} else {
ret = ECOMMON;
}
goto out;
}
out:
lcrc_start_response_free(response);
response = NULL;
return ret;
}
/*
* Create a create request message and call RPC
*/
int client_start(const struct client_arguments *args, bool *reset_tty, struct termios *oldtios,
struct command_fifo_config **console_fifos)
{
int ret = 0;
ret = start_cmd_init(args);
if (ret != 0) {
return ret;
}
if (oldtios != NULL && console_fifos != NULL && reset_tty != NULL) {
ret = start_prepare_console(args, oldtios, reset_tty, console_fifos);
if (ret != 0) {
goto out;
}
}
ret = do_client_start(args, console_fifos);
if (ret != 0) {
goto out;
}
out:
return ret;
}
void client_wait_fifo_exit(const struct client_arguments *args)
{
if (args->custom_conf.attach_stdin || args->custom_conf.attach_stdout || args->custom_conf.attach_stderr) {
sem_wait(&g_console_waitexit_sem);
}
}
void client_restore_console(bool reset_tty, const struct termios *oldtios, struct command_fifo_config *console_fifos)
{
if (reset_tty && tcsetattr(0, TCSAFLUSH, oldtios) < 0) {
WARN("Failed to reset terminal properties: %s.", strerror(errno));
}
free_command_fifo_config(console_fifos);
sem_destroy(&g_console_waitopen_sem);
sem_destroy(&g_console_waitexit_sem);
}
int cmd_start_main(int argc, const char **argv)
{
int ret = 0;
int i = 0;
struct log_config lconf = { 0 };
command_t cmd;
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_start_args)
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_start_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_start_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_start_desc,
g_cmd_start_usage);
if (command_parse_args(&cmd, &g_cmd_start_args.argc, &g_cmd_start_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Start: log init failed");
exit(ECOMMON);
}
if (g_cmd_start_args.argc == 0) {
COMMAND_ERROR("\"start\" requires at least 1 argument");
exit(EINVALIDARGS);
}
if (g_cmd_start_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to start.");
exit(EINVALIDARGS);
}
for (i = 0; i < g_cmd_start_args.argc; i++) {
g_cmd_start_args.name = g_cmd_start_args.argv[i];
if (client_start(&g_cmd_start_args, NULL, NULL, NULL)) {
ERROR("Container \"%s\" start failed", g_cmd_start_args.name);
ret = ECOMMON;
continue;
}
if (g_cmd_start_args.detach) {
printf("Container \"%s\" started\n", g_cmd_start_args.name);
}
}
return ret;
}

31
src/cmd/lcrc/base/start.h Normal file
View File

@ -0,0 +1,31 @@
/******************************************************************************
* 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: maoweiyong
* Create: 2018-11-08
* Description: provide container start definition
******************************************************************************/
#ifndef __CMD_START_H
#define __CMD_START_H
#include "arguments.h"
#include "commands.h"
#include <termios.h>
extern const char g_cmd_start_desc[];
extern struct client_arguments g_cmd_start_args;
void client_wait_fifo_exit(const struct client_arguments *args);
void client_restore_console(bool reset_tty, const struct termios *oldtios, struct command_fifo_config *console_fifos);
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);
#endif /* __CMD_START_H */

123
src/cmd/lcrc/base/stop.c Normal file
View File

@ -0,0 +1,123 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container stop functions
******************************************************************************/
#include "stop.h"
#include "securec.h"
#include "arguments.h"
#include "log.h"
#include "utils.h"
#include "lcrc_connect.h"
const char g_cmd_stop_desc[] = "Stop one or more containers";
const char g_cmd_stop_usage[] = "stop [OPTIONS] CONTAINER [CONTAINER...]";
struct client_arguments g_cmd_stop_args = {
.force = false,
.time = 10,
};
/*
* Create a stop request message and call RPC
*/
static int client_stop(const struct client_arguments *args)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
struct lcrc_stop_request request = { 0 };
struct lcrc_stop_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(struct lcrc_stop_response));
if (response == NULL) {
ERROR("Stop: Out of memory");
return -1;
}
request.name = args->name;
request.force = args->force;
request.timeout = args->time;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.stop) {
ERROR("Unimplemented stop op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.stop(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
out:
lcrc_stop_response_free(response);
return ret;
}
int cmd_stop_main(int argc, const char **argv)
{
int i = 0;
int status = 0;
struct log_config lconf = { 0 };
command_t cmd;
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_stop_args),
STOP_OPTIONS(g_cmd_stop_args)
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_stop_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_stop_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_stop_desc,
g_cmd_stop_usage);
if (command_parse_args(&cmd, &g_cmd_stop_args.argc, &g_cmd_stop_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("log init failed");
exit(ECOMMON);
}
if (g_cmd_stop_args.force) {
g_cmd_stop_args.time = 0;
}
if (g_cmd_stop_args.argc == 0) {
COMMAND_ERROR("Stop requires minimum of 1 container name");
exit(EINVALIDARGS);
}
if (g_cmd_stop_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to stop.");
exit(EINVALIDARGS);
}
for (i = 0; i < g_cmd_stop_args.argc; i++) {
g_cmd_stop_args.name = g_cmd_stop_args.argv[i];
if (client_stop(&g_cmd_stop_args)) {
ERROR("Container \"%s\" stop failed", g_cmd_stop_args.name);
status = -1;
continue;
}
printf("%s\n", g_cmd_stop_args.name);
}
if (status) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

31
src/cmd/lcrc/base/stop.h Normal file
View File

@ -0,0 +1,31 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container stop definition
******************************************************************************/
#ifndef __CMD_STOP_H
#define __CMD_STOP_H
#include "arguments.h"
#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 }
extern const char g_cmd_stop_desc[];
extern const char g_cmd_stop_usage[];
extern struct client_arguments g_cmd_stop_args;
int cmd_stop_main(int argc, const char **argv);
#endif /* __CMD_STOP_H */

432
src/cmd/lcrc/commands.c Normal file
View File

@ -0,0 +1,432 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: lifeng
* Create: 2017-11-22
* Description: provide container command functions
******************************************************************************/
#include "commands.h"
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <pthread.h>
#include <syslog.h>
#include "securec.h"
#include "arguments.h"
#include "config.h"
#include "log.h"
#include "utils.h"
#include "console.h"
#include "constants.h"
static void send_msg_to_syslog(int argc, const char **argv)
{
int nret = 0;
int fd = -1;
int i = 0;
bool found = false;
ssize_t len = 0;
pid_t ppid = -1;
char cmdline_path[PATH_MAX] = { 0 };
char cmdline[MAX_BUFFER_SIZE + 1] = { 0 };
char *msg = NULL;
const char *target_command[] = { "kill", "restart", "rm", "stop", NULL };
if (argc < 2) {
COMMAND_ERROR("Invalid arguments to send syslog");
return;
}
for (; target_command[i] != NULL; i++) {
if (strcmp(argv[1], target_command[i]) == 0) {
found = true;
}
}
if (!found) {
return;
}
ppid = getppid();
// get parent cmdline, "/proc/ppid/cmdline"
nret = sprintf_s(cmdline_path, PATH_MAX, "/proc/%d/cmdline", ppid);
if (nret < 0) {
COMMAND_ERROR("Get parent '%d' cmdline path failed", ppid);
return;
}
fd = util_open(cmdline_path, O_RDONLY, DEFAULT_SECURE_FILE_MODE);
if (fd < 0) {
COMMAND_ERROR("Open parent '%d' cmdline path failed", ppid);
return;
}
len = util_read_nointr(fd, cmdline, MAX_BUFFER_SIZE);
if (len < 0) {
COMMAND_ERROR("Read cmdline failed");
goto free_out;
}
msg = util_string_join(" ", argv, (size_t)argc);
if (msg == NULL) {
msg = util_strdup_s(argv[1]);
}
openlog("isulad-client", LOG_PID, LOG_USER);
syslog(LOG_DEBUG, "received command [%s] from parent [%d] cmdline [%s]", msg, ppid, cmdline);
closelog();
free_out:
close(fd);
free(msg);
}
static void print_version()
{
printf("Version %s, commit %s\n", VERSION, LCRD_GIT_COMMIT);
}
/* compare commands */
int compare_commands(const void *s1, const void *s2)
{
return strcmp((*(const struct command *)s1).name, (*(const struct command *)s2).name);
}
const struct command *command_by_name(const struct command *cmds, const char * const name)
{
size_t i = 0;
if (cmds == NULL) {
return NULL;
}
while (1) {
if (cmds[i].name == NULL) {
return NULL;
}
if (strcmp(cmds[i].name, name) == 0) {
return cmds + i;
}
++i;
}
}
// Default help command if implementation doesn't provide one
int command_default_help(const char * const program_name, struct command *commands, int argc, const char **argv)
{
const struct command *command = NULL;
if (commands == NULL) {
return 1;
}
if (argc == 0) {
size_t i = 0;
size_t max_size = 0;
printf("USAGE:\n");
printf("\t%s <command> [args...]\n", program_name);
printf("\n");
printf("COMMANDS:\n");
for (i = 0; commands[i].name != NULL; i++) {
size_t cmd_size = strlen(commands[i].name);
if (cmd_size > max_size) {
max_size = cmd_size;
}
}
qsort(commands, i, sizeof(commands[0]), compare_commands);
for (i = 0; commands[i].name != NULL; i++) {
printf("\t%*s\t%s\n", -(int)max_size, commands[i].name, commands[i].description);
}
printf("\n");
print_common_help();
return 0;
} else if (argc > 1) {
printf("%s: unrecognized argument: \"%s\"\n", program_name, argv[1]);
return 1;
}
command = command_by_name(commands, argv[0]);
if (command == NULL) {
printf("%s: sub-command \"%s\" not found\n", program_name, argv[0]);
printf("run `lcrc --help` for a list of sub-commands\n");
return 1;
}
if (command->longdesc != NULL) {
printf("%s\n", command->longdesc);
}
return 0;
}
/* run command */
int run_command(struct command *commands, int argc, const char **argv)
{
const struct command *command = NULL;
if (argc == 1) {
return command_default_help(argv[0], commands, argc - 1, (const char **)(argv + 1));
}
if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
// lcrc help command format: lcrc [-h|help|--help] args
return command_default_help(argv[0], commands, argc - 2, (const char **)(argv + 2));
}
if (strcmp(argv[1], "--version") == 0) {
print_version();
return 0;
}
command = command_by_name(commands, argv[1]);
if (command != NULL) {
send_msg_to_syslog(argc, argv);
return command->executor(argc, (const char **)argv);
}
printf("%s: command \"%s\" not found\n", argv[0], argv[1]);
printf("run `%s --help` or `run -h` for a list of sub-commands\n", argv[0]);
return 1;
}
/* free command fifo names */
void free_command_fifo_config(struct command_fifo_config *fifos)
{
if (fifos != NULL) {
if (fifos->stdin_path != NULL) {
free(fifos->stdin_path);
fifos->stdin_path = NULL;
}
if (fifos->stdout_path != NULL) {
free(fifos->stdout_path);
fifos->stdout_path = NULL;
}
if (fifos->stderr_path != NULL) {
free(fifos->stderr_path);
fifos->stderr_path = NULL;
}
if (fifos->stdin_name != NULL) {
free(fifos->stdin_name);
fifos->stdin_name = NULL;
}
if (fifos->stdout_name != NULL) {
free(fifos->stdout_name);
fifos->stdout_name = NULL;
}
if (fifos->stderr_name != NULL) {
free(fifos->stderr_name);
fifos->stderr_name = NULL;
}
free(fifos);
}
}
/* delete command fifo */
void delete_command_fifo(struct command_fifo_config *fifos)
{
int ret;
if (fifos == NULL) {
return;
}
ret = console_fifo_delete(fifos->stdin_name);
if (ret) {
WARN("Delete fifo failed: %s", fifos->stdin_name);
}
ret = console_fifo_delete(fifos->stdout_name);
if (ret) {
WARN("Delete fifo failed: %s", fifos->stdout_name);
}
ret = console_fifo_delete(fifos->stderr_name);
if (ret) {
WARN("Delete fifo failed: %s", fifos->stderr_name);
}
ret = util_recursive_rmdir(fifos->stdin_path, 0);
if (ret) {
WARN("Remove directory failed: %s", fifos->stdin_path);
}
ret = util_recursive_rmdir(fifos->stdout_path, 0);
if (ret) {
WARN("Remove directory failed: %s", fifos->stdout_path);
}
ret = util_recursive_rmdir(fifos->stderr_path, 0);
if (ret) {
WARN("Remove directory failed: %s", fifos->stderr_path);
}
free_command_fifo_config(fifos);
}
static int do_create_console_fifo(const char *subpath, const char *stdflag, char **out_fifo_dir, char **out_fifo_name)
{
int ret = 0;
char fifo_dir[PATH_MAX] = { 0 };
char fifo_name[PATH_MAX] = { 0 };
ret = console_fifo_name(CLIENT_RUNDIR, subpath, stdflag, fifo_name, sizeof(fifo_name), fifo_dir,
sizeof(fifo_dir), true);
if (ret != 0) {
ERROR("Failed to get console fifo name.");
ret = -1;
goto out;
}
if (console_fifo_create(fifo_name)) {
ERROR("Failed to create console fifo.");
ret = -1;
goto out;
}
*out_fifo_dir = util_strdup_s(fifo_dir);
*out_fifo_name = util_strdup_s(fifo_name);
out:
return ret;
}
int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type,
struct command_fifo_config **pconsole_fifos)
{
int ret = 0;
char subpath[PATH_MAX] = { 0 };
struct command_fifo_config *fifos = NULL;
fifos = util_common_calloc_s(sizeof(struct command_fifo_config));
if (fifos == NULL) {
ERROR("Failed to malloc memory for FIFO names.");
return -1;
}
ret = sprintf_s(subpath, sizeof(subpath), "%s/%s-%u-%u", name, type, (unsigned int)getpid(),
(unsigned int)pthread_self());
if (ret < 0) {
ERROR("Path is too long");
goto cleanup;
}
if (attach_stdin) {
ret = do_create_console_fifo(subpath, "in", &fifos->stdin_path, &fifos->stdin_name);
if (ret != 0) {
goto cleanup;
}
INFO("FIFO:%s create for start success.", fifos->stdin_name);
}
if (attach_stdout) {
ret = do_create_console_fifo(subpath, "out", &fifos->stdout_path, &fifos->stdout_name);
if (ret != 0) {
goto cleanup;
}
INFO("FIFO:%s create for start success.", fifos->stdout_name);
}
if (attach_stderr) {
ret = do_create_console_fifo(subpath, "err", &fifos->stderr_path, &fifos->stderr_name);
if (ret != 0) {
goto cleanup;
}
INFO("FIFO:%s create for start success.", fifos->stderr_name);
}
*pconsole_fifos = fifos;
return 0;
cleanup:
console_fifo_delete(fifos->stdin_name);
console_fifo_delete(fifos->stdout_name);
console_fifo_delete(fifos->stderr_name);
free_command_fifo_config(fifos);
return -1;
}
struct console_loop_thread_args {
struct command_fifo_config *fifo_config;
bool tty;
};
static void *client_console_loop_thread(void *arg)
{
int ret = 0;
int fifoinfd = -1;
int fifooutfd = -1;
int fifoerrfd = -1;
const struct console_loop_thread_args *args = arg;
bool tty = args->tty;
struct command_fifo_config *fifo_config = args->fifo_config;
sem_t *wait_open = fifo_config->wait_open;
sem_t *wait_exit = fifo_config->wait_exit;
ret = pthread_detach(pthread_self());
if (ret != 0) {
CRIT("Start: set thread detach fail");
goto err1;
}
if (fifo_config->stdin_name) {
if (console_fifo_open_withlock(fifo_config->stdin_name, &fifoinfd, O_RDWR | O_NONBLOCK)) {
ERROR("Start: failed to open console fifo.");
goto err2;
}
INFO("FIFO:%s open success for start.", fifo_config->stdin_name);
}
if (fifo_config->stdout_name) {
if (console_fifo_open(fifo_config->stdout_name, &fifooutfd, O_RDONLY | O_NONBLOCK)) {
ERROR("Failed to open console fifo.");
goto err2;
}
INFO("FIFO:%s open success for start.", fifo_config->stdout_name);
}
if (fifo_config->stderr_name) {
if (console_fifo_open(fifo_config->stderr_name, &fifoerrfd, O_RDONLY | O_NONBLOCK)) {
ERROR("Start: failed to open console fifo.");
goto err2;
}
INFO("FIFO:%s open success for start.", fifo_config->stderr_name);
}
sem_post(wait_open);
client_console_loop(0, 1, 2, fifoinfd, fifooutfd, fifoerrfd, 1, tty);
err2:
if (fifoinfd >= 0) {
console_fifo_close(fifoinfd);
}
if (fifooutfd >= 0) {
console_fifo_close(fifooutfd);
}
if (fifoerrfd >= 0) {
console_fifo_close(fifoerrfd);
}
err1:
sem_post(wait_open);
sem_post(wait_exit);
return NULL;
}
int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty)
{
int res = 0;
pthread_t a_thread;
struct console_loop_thread_args args;
args.fifo_config = console_fifos;
args.tty = tty;
res = pthread_create(&a_thread, NULL, client_console_loop_thread, (void *)(&args));
if (res != 0) {
CRIT("Thread creation failed");
return -1;
}
sem_wait(console_fifos->wait_open);
return 0;
}

72
src/cmd/lcrc/commands.h Normal file
View File

@ -0,0 +1,72 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: lifeng
* Create: 2017-11-22
* Description: provide container commands definition
******************************************************************************/
#ifndef __COMMAND_H
#define __COMMAND_H
#include "arguments.h"
#include <semaphore.h>
#define CLIENT_RUNDIR "/var/run/lcrc"
// A command is described by:
// @name: The name which should be passed as a second parameter
// @executor: The function that will be executed if the command
// matches. Receives the argc of the program minus two, and
// the rest os argv
// @description: Brief description, will show in help messages
// @longdesc: Long descripton to show when you run `help <command>`
struct command {
const char * const name;
int(*executor)(int, const char **);
const char * const description;
const char * const longdesc;
struct client_arguments *args;
};
struct command_fifo_config {
char *stdin_path;
char *stdout_path;
char *stderr_path;
char *stdin_name;
char *stdout_name;
char *stderr_name;
sem_t *wait_open;
sem_t *wait_exit;
};
int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name,
const char *type, struct command_fifo_config **pconsole_fifos);
int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty);
void free_command_fifo_config(struct command_fifo_config *fifos);
void delete_command_fifo(struct command_fifo_config *fifos);
// Gets a pointer to a command, to allow implementing custom behavior
// returns null if not found.
//
// NOTE: Command arrays must end in a command with all member is NULL
const struct command *command_by_name(const struct command *cmds,
const char * const name);
// Default help command if implementation doesn't prvide one
int commmand_default_help(const char * const program_name,
struct command *commands,
int argc,
const char **argv);
int run_command(struct command *commands, int argc, const char **argv);
#endif /* __COMMAND_H */

View File

@ -0,0 +1,7 @@
# get current directory sources files
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} lcrc_extend_srcs)
set(LCRC_EXTEND_SRCS
${lcrc_extend_srcs}
PARENT_SCOPE
)

View File

@ -0,0 +1,172 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container events functions
******************************************************************************/
#include "error.h"
#include "events.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
#include "securec.h"
const char g_cmd_events_desc[] = "Get real time events from the server";
const char g_cmd_events_usage[] = "events [command options]";
struct client_arguments g_cmd_events_args = {
.since = NULL,
.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)
{
if (sta > EVENTS_TYPE_PAUSED1) {
return NULL;
}
return g_strtype[sta];
}
static void print_events_callback(const container_events_format_t *event)
{
char timebuffer[512] = { 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 (event->has_type) {
printf("%-15s %s\n", "EventType:", lcrsta2str(event->type));
} else {
printf("%-15s %s\n", "EventType:", "-");
}
if (event->has_pid) {
printf("%-15s %u\n", "Pid:", event->pid);
} else {
printf("%-15s %s\n", "Pid:", "-");
}
if (event->has_exit_status) {
printf("%-15s %u\n", "Exit_Status:", event->exit_status);
} else {
printf("%-15s %s\n", "Exit_Status:", "-");
}
}
/*
* Create a delete request message and call RPC
*/
static int client_event(struct client_arguments *args)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
struct lcrc_events_request request = { 0 };
struct lcrc_events_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(struct lcrc_events_response));
if (response == NULL) {
ERROR("Event: Out of memory");
return -1;
}
request.cb = print_events_callback;
request.id = args->name;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.events) {
ERROR("Unimplemented event op");
ret = -1;
goto out;
}
if (args->since && !get_timestamp(args->since, &request.since)) {
COMMAND_ERROR("Failed to get since timestamp");
ret = -1;
goto out;
}
if (args->until && !get_timestamp(args->until, &request.until)) {
COMMAND_ERROR("Failed to get until timestamp");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.events(&request, response, &config);
if (ret) {
COMMAND_ERROR("Failed to get container events, %s",
response->errmsg ? response->errmsg : errno_to_error_message(response->cc));
}
out:
lcrc_events_response_free(response);
return ret;
}
int cmd_events_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
command_t cmd;
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_events_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_events_args.progname = argv[0];
struct command_option options[] = {
LOG_OPTIONS(lconf),
EVENTS_OPTIONS(g_cmd_events_args),
COMMON_OPTIONS(g_cmd_events_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_events_desc,
g_cmd_events_usage);
if (command_parse_args(&cmd, &g_cmd_events_args.argc, &g_cmd_events_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Events: log init failed");
exit(ECOMMON);
}
if (g_cmd_events_args.socket == NULL) {
COMMAND_ERROR("Missing --host,-H option");
exit(EINVALIDARGS);
}
if (client_event(&g_cmd_events_args)) {
if (g_cmd_events_args.name != NULL) {
ERROR("Container \"%s\" event failed", g_cmd_events_args.name);
} else {
ERROR("Container events failed");
}
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,33 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container events definition
******************************************************************************/
#ifndef __CMD_EVENT_H
#define __CMD_EVENT_H
#include "arguments.h"
#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 }, \
{ CMD_OPT_TYPE_STRING, false, "until", 'U', &(cmdargs).until, \
"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);
#endif /* __CMD_EVENT_H */

View File

@ -0,0 +1,133 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2019-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: wangfengtu
* Create: 2019-04-04
* Description: provide container export functions
******************************************************************************/
#include "export.h"
#include <limits.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_export_desc[] = "export container";
const char g_cmd_export_usage[] = "export [command options] [ID|NAME]";
struct client_arguments g_cmd_export_args = {};
/*
* Create a export request message and call RPC
*/
static int client_export(const struct client_arguments *args)
{
int ret = 0;
errno_t mret;
lcrc_connect_ops *ops = NULL;
struct lcrc_export_request request;
struct lcrc_export_response *response = NULL;
client_connect_config_t config = { 0 };
mret = memset_s(&request, sizeof(request), 0x00, sizeof(request));
if (mret != EOK) {
ERROR("Failed to memset export request");
return -1;
}
response = util_common_calloc_s(sizeof(struct lcrc_export_response));
if (response == NULL) {
ERROR("Resume: Out of memory");
return -1;
}
request.name = args->name;
request.file = args->file;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.export_rootfs) {
ERROR("Unimplemented export op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.export_rootfs(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
out:
lcrc_export_response_free(response);
return ret;
}
int cmd_export_main(int argc, const char **argv)
{
int i = 0;
char file[PATH_MAX] = { 0 };
struct log_config lconf = { 0 };
lconf.name = argv[0];
lconf.quiet = true;
lconf.driver = "stdout";
lconf.file = NULL;
lconf.priority = "ERROR";
if (log_init(&lconf)) {
COMMAND_ERROR("Export: log init failed");
exit(ECOMMON);
}
command_t cmd;
if (client_arguments_init(&g_cmd_export_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_export_args.progname = argv[0];
struct command_option options[] = { COMMON_OPTIONS(g_cmd_export_args), EXPORT_OPTIONS(g_cmd_export_args) };
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_export_desc,
g_cmd_export_usage);
if (command_parse_args(&cmd, &g_cmd_export_args.argc, &g_cmd_export_args.argv)) {
exit(EINVALIDARGS);
}
if (g_cmd_export_args.argc != 1) {
COMMAND_ERROR("Export requires exactly 1 container name");
exit(EINVALIDARGS);
}
if (g_cmd_export_args.file == NULL) {
COMMAND_ERROR("Missing output file, use -o,--output option");
exit(EINVALIDARGS);
}
/* If it's not a absolute path, add cwd to be absolute path */
if (g_cmd_export_args.file[0] != '/') {
char cwd[PATH_MAX] = { 0 };
if (!getcwd(cwd, sizeof(cwd))) {
COMMAND_ERROR("get cwd failed:%s", strerror(errno));
exit(ECOMMON);
}
if (sprintf_s(file, sizeof(file), "%s/%s", cwd, g_cmd_export_args.file) < 0) {
COMMAND_ERROR("filename too long");
exit(EINVALIDARGS);
}
g_cmd_export_args.file = file;
}
g_cmd_export_args.name = g_cmd_export_args.argv[i];
if (client_export(&g_cmd_export_args)) {
ERROR("Container \"%s\" export failed", g_cmd_export_args.name);
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,28 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2019-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: wangfengtu
* Create: 2019-04-04
* Description: provide container resume definition
******************************************************************************/
#ifndef __CMD_EXPORT_H
#define __CMD_EXPORT_H
#include "arguments.h"
#define EXPORT_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_STRING, false, "output", 'o', &(cmdargs).file, "Write to a file", NULL }
extern const char g_cmd_export_desc[];
extern const char g_cmd_export_usage[];
extern struct client_arguments g_cmd_export_args;
int cmd_export_main(int argc, const char **argv);
#endif

118
src/cmd/lcrc/extend/pause.c Normal file
View File

@ -0,0 +1,118 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container pause functions
******************************************************************************/
#include "pause.h"
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_pause_desc[] = "Pause all processes within one or more containers";
const char g_cmd_pause_usage[] = "pause [OPTIONS] CONTAINER [CONTAINER...]";
struct client_arguments g_cmd_pause_args = {};
/*
* Create a pause request message and call RPC
*/
static int client_pause(const struct client_arguments *args)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
struct lcrc_pause_request request = { 0 };
struct lcrc_pause_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(struct lcrc_pause_response));
if (response == NULL) {
ERROR("Pause: Out of memory");
return -1;
}
request.name = args->name;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.pause) {
ERROR("Unimplemented pause op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.pause(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
out:
lcrc_pause_response_free(response);
return ret;
}
int cmd_pause_main(int argc, const char **argv)
{
int i = 0;
int status = 0;
struct log_config lconf = { 0 };
lconf.name = argv[0];
lconf.quiet = true;
lconf.file = NULL;
lconf.priority = "ERROR";
lconf.driver = "stdout";
if (log_init(&lconf)) {
COMMAND_ERROR("log init failed");
exit(ECOMMON);
}
command_t cmd;
if (client_arguments_init(&g_cmd_pause_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_pause_args.progname = argv[0];
struct command_option options[] = { COMMON_OPTIONS(g_cmd_pause_args) };
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_pause_desc,
g_cmd_pause_usage);
if (command_parse_args(&cmd, &g_cmd_pause_args.argc, &g_cmd_pause_args.argv)) {
exit(EINVALIDARGS);
}
if (g_cmd_pause_args.argc == 0) {
COMMAND_ERROR("Pause requires at least 1 container names");
exit(EINVALIDARGS);
}
if (g_cmd_pause_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to pause.");
exit(EINVALIDARGS);
}
for (i = 0; i < g_cmd_pause_args.argc; i++) {
g_cmd_pause_args.name = g_cmd_pause_args.argv[i];
if (client_pause(&g_cmd_pause_args)) {
ERROR("Container \"%s\" pause failed", g_cmd_pause_args.name);
status = -1;
continue;
}
printf("%s\n", g_cmd_pause_args.name);
}
if (status) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container pause definition
******************************************************************************/
#ifndef __CMD_PAUSE_H
#define __CMD_PAUSE_H
#include "arguments.h"
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);
#endif

View File

@ -0,0 +1,118 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container resume functions
******************************************************************************/
#include "resume.h"
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_resume_desc[] = "resume container";
const char g_cmd_resume_usage[] = "resume [command options] --name=NAME";
struct client_arguments g_cmd_resume_args = {};
/*
* Create a resume request message and call RPC
*/
static int client_resume(const struct client_arguments *args)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
struct lcrc_resume_request request = { 0 };
struct lcrc_resume_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(struct lcrc_resume_response));
if (response == NULL) {
ERROR("Resume: Out of memory");
return -1;
}
request.name = args->name;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.resume) {
ERROR("Unimplemented resume op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.resume(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
out:
lcrc_resume_response_free(response);
return ret;
}
int cmd_resume_main(int argc, const char **argv)
{
int i = 0;
int status = 0;
struct log_config lconf = { 0 };
lconf.name = argv[0];
lconf.quiet = true;
lconf.driver = "stdout";
lconf.file = NULL;
lconf.priority = "ERROR";
if (log_init(&lconf)) {
COMMAND_ERROR("Resume: log init failed");
exit(ECOMMON);
}
command_t cmd;
if (client_arguments_init(&g_cmd_resume_args)) {
COMMAND_ERROR("client arguments init failed\n");
exit(ECOMMON);
}
g_cmd_resume_args.progname = argv[0];
struct command_option options[] = { COMMON_OPTIONS(g_cmd_resume_args) };
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_resume_desc,
g_cmd_resume_usage);
if (command_parse_args(&cmd, &g_cmd_resume_args.argc, &g_cmd_resume_args.argv)) {
exit(EINVALIDARGS);
}
if (g_cmd_resume_args.argc == 0) {
COMMAND_ERROR("Pause requires at least 1 container names");
exit(EINVALIDARGS);
}
if (g_cmd_resume_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to resume.");
exit(EINVALIDARGS);
}
for (i = 0; i < g_cmd_resume_args.argc; i++) {
g_cmd_resume_args.name = g_cmd_resume_args.argv[i];
if (client_resume(&g_cmd_resume_args)) {
ERROR("Container \"%s\" resume failed", g_cmd_resume_args.name);
status = -1;
continue;
}
printf("%s\n", g_cmd_resume_args.name);
}
if (status) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container resume definition
******************************************************************************/
#ifndef __CMD_RESUME_H
#define __CMD_RESUME_H
#include "arguments.h"
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);
#endif

258
src/cmd/lcrc/extend/stats.c Normal file
View File

@ -0,0 +1,258 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container stats functions
******************************************************************************/
#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <termios.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include "error.h"
#include "securec.h"
#include "arguments.h"
#include "stats.h"
#include "utils.h"
#include "log.h"
#include "lcrc_connect.h"
#define ESC "\033"
#define TERMCLEAR ESC "[H" ESC "[J"
#define TERMNORM ESC "[0m"
#define TERMBOLD ESC "[1m"
#define TERMRVRS ESC "[7m"
const char g_cmd_stats_desc[] = "Display a live stream of container(s) resource usage statistics";
const char g_cmd_stats_usage[] = "stats [OPTIONS] [CONTAINER...]";
struct client_arguments g_cmd_stats_args = {
.showall = false,
.nostream = false,
.runtime = "lcr",
};
static struct lcrc_stats_response *g_oldstats = NULL;
static void lcrc_size_humanize(unsigned long long val, char *buf, size_t bufsz)
{
int ret = 0;
if (val > 1024 * 1024 * 1024) {
ret = sprintf_s(buf, bufsz, "%u.%.2u GiB", (unsigned int)(val >> 30),
(unsigned int)(val & ((1 << 30) - 1)) / 10737419);
} else if (val > 1024 * 1024) {
unsigned long long x = val + 5243; /* for rounding */
ret = sprintf_s(buf, bufsz, "%u.%.2u MiB", (unsigned int)(x >> 20),
(unsigned int)(((x & ((1 << 20) - 1)) * 100) >> 20));
} else if (val > 1024) {
unsigned long long x = val + 5; /* for rounding */
ret = sprintf_s(buf, bufsz, "%u.%.2u KiB", (unsigned int)(x >> 10),
(unsigned int)(((x & ((1 << 10) - 1)) * 100) >> 10));
} else {
ret = sprintf_s(buf, bufsz, "%u.00 B", (unsigned int)val);
}
if (ret < 0) {
ERROR("Humanize sprintf failed!");
}
}
static void stats_print_header(void)
{
printf(TERMRVRS TERMBOLD);
printf("%-16s %-10s %-26s %-10s %-26s %-10s", "CONTAINER", "CPU %", "MEM USAGE / LIMIT", "MEM %",
"BLOCK I / O", "PIDS");
printf("\n");
printf(TERMNORM);
}
static void stats_print(const struct lcrc_container_info *stats)
{
#define SHORTIDLEN 12
#define PERCENT 100
char iosb_str[63];
char iosb_read_str[20];
char iosb_write_str[20];
char mem_str[63];
char mem_used_str[20];
char mem_limit_str[20];
int len;
double cpu_percent = 0.0;
char *short_id = NULL;
lcrc_size_humanize(stats->blkio_read, iosb_read_str, sizeof(iosb_read_str));
lcrc_size_humanize(stats->blkio_write, iosb_write_str, sizeof(iosb_write_str));
lcrc_size_humanize(stats->mem_used, mem_used_str, sizeof(mem_used_str));
lcrc_size_humanize(stats->mem_limit, mem_limit_str, sizeof(mem_limit_str));
len = sprintf_s(iosb_str, sizeof(iosb_str), "%s / %s", iosb_read_str, iosb_write_str);
if (len < 0) {
ERROR("Sprintf iosb_str failed");
return;
}
len = sprintf_s(mem_str, sizeof(mem_str), "%s / %s", mem_used_str, mem_limit_str);
if (len < 0) {
ERROR("Sprintf mem_str failed");
return;
}
if (g_oldstats != NULL) {
size_t i;
uint64_t d_sys_use = 0;
uint64_t d_cpu_use = 0;
for (i = 0; i < g_oldstats->container_num; i++) {
if (strcmp(stats->id, g_oldstats->container_stats[i].id) != 0) {
continue;
}
if (stats->cpu_system_use > g_oldstats->container_stats[i].cpu_system_use) {
d_sys_use = stats->cpu_system_use - g_oldstats->container_stats[i].cpu_system_use;
}
if (stats->cpu_use_nanos > g_oldstats->container_stats[i].cpu_use_nanos) {
d_cpu_use = stats->cpu_use_nanos - g_oldstats->container_stats[i].cpu_use_nanos;
}
if (d_sys_use > 0 && stats->online_cpus > 0) {
cpu_percent = ((double)d_cpu_use / d_sys_use) * stats->online_cpus * PERCENT;
}
}
}
short_id = util_strdup_s(stats->id);
if (strlen(short_id) > SHORTIDLEN) {
short_id[SHORTIDLEN] = '\0';
}
printf("%-16s %-10.2f %-26s %-10.2f %-26s %-10llu", short_id, cpu_percent, mem_str,
stats->mem_limit ? ((double)stats->mem_used / stats->mem_limit) * PERCENT : 0.00, iosb_str,
(unsigned long long)stats->pids_current);
free(short_id);
}
static void stats_output(const struct client_arguments *args, struct lcrc_stats_response **response)
{
size_t i;
printf(TERMCLEAR);
stats_print_header();
for (i = 0; i < (*response)->container_num; i++) {
stats_print(&((*response)->container_stats[i]));
printf("\n");
}
fflush(stdout);
lcrc_stats_response_free(g_oldstats);
g_oldstats = *response;
*response = NULL;
}
static int client_stats_mainloop(const struct client_arguments *args, const struct lcrc_stats_request *request)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
client_connect_config_t config;
if (args == NULL) {
return -1;
}
ops = get_connect_client_ops();
if (ops == NULL || ops->container.stats == NULL) {
ERROR("Unimplemented ops");
return -1;
}
config = get_connect_config(args);
while (1) {
struct lcrc_stats_response *response = NULL;
response = util_common_calloc_s(sizeof(struct lcrc_stats_response));
if (response == NULL) {
ERROR("Out of memory");
ret = -1;
goto err_out;
}
ret = ops->container.stats(request, response, &config);
if (ret) {
ERROR("Failed to stats containers info");
client_print_error(response->cc, response->server_errono, response->errmsg);
lcrc_stats_response_free(response);
ret = -1;
goto err_out;
}
stats_output(args, &response);
lcrc_stats_response_free(response);
if (args->nostream) {
goto err_out;
}
sleep(1);
}
err_out:
lcrc_stats_response_free(g_oldstats);
g_oldstats = NULL;
return ret;
}
/*
* Create a stats request message and call RPC
*/
static int client_stats(const struct client_arguments *args)
{
struct lcrc_stats_request request = { 0 };
request.runtime = args->runtime;
request.all = args->showall;
request.containers = (char **)(args->argv);
request.containers_len = (size_t)(args->argc);
return client_stats_mainloop(args, &request);
}
int cmd_stats_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
command_t cmd;
struct command_option options[] = {
LOG_OPTIONS(lconf),
STATUS_OPTIONS(g_cmd_stats_args),
COMMON_OPTIONS(g_cmd_stats_args)
};
if (client_arguments_init(&g_cmd_stats_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_stats_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_stats_desc,
g_cmd_stats_usage);
set_default_command_log_config(argv[0], &lconf);
if (command_parse_args(&cmd, &g_cmd_stats_args.argc, &g_cmd_stats_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Stats: log init failed");
exit(ECOMMON);
}
if (client_stats(&g_cmd_stats_args)) {
ERROR("Can not stats containers");
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,33 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container stats definition
******************************************************************************/
#ifndef __CMD_STATS_H
#define __CMD_STATS_H
#include "arguments.h"
#define STATUS_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_STRING, false, "runtime", 'R', &(cmdargs).runtime, \
"Runtime to use for containers(default: lcr)", NULL }, \
{ 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 }
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);
#endif /* __CMD_STATS_H */

View File

@ -0,0 +1,166 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container update functions
******************************************************************************/
#include <string.h>
#include <errno.h>
#include "securec.h"
#include "arguments.h"
#include "update.h"
#include "utils.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_update_desc[] = "Update configuration of one or more containers";
const char g_cmd_update_usage[] = "update [OPTIONS] CONTAINER [CONTAINER...]";
struct client_arguments g_cmd_update_args = {
.restart = NULL,
};
static int pack_update_request(const struct client_arguments *args, struct lcrc_update_request *request)
{
int ret = 0;
request->updateconfig->restart_policy = args->restart;
request->updateconfig->cr->blkio_weight = args->cr.blkio_weight;
request->updateconfig->cr->cpu_shares = args->cr.cpu_shares;
request->updateconfig->cr->cpu_period = args->cr.cpu_period;
request->updateconfig->cr->cpu_quota = args->cr.cpu_quota;
request->updateconfig->cr->cpuset_cpus = args->cr.cpuset_cpus;
request->updateconfig->cr->cpuset_mems = args->cr.cpuset_mems;
request->updateconfig->cr->memory = args->cr.memory_limit;
request->updateconfig->cr->memory_swap = args->cr.memory_swap;
request->updateconfig->cr->memory_reservation = args->cr.memory_reservation;
request->updateconfig->cr->kernel_memory = args->cr.kernel_memory_limit;
return ret;
}
static int client_update(const struct client_arguments *args)
{
int ret = 0;
lcrc_connect_ops *ops = NULL;
container_cgroup_resources_t cr = { 0 };
lcrc_update_config_t updateconfig = { 0 };
struct lcrc_update_request request = { 0 };
struct lcrc_update_response *response = NULL;
client_connect_config_t config = { 0 };
response = util_common_calloc_s(sizeof(struct lcrc_update_response));
if (response == NULL) {
ERROR("Out of memory");
return -1;
}
updateconfig.cr = &cr;
request.updateconfig = &updateconfig;
request.name = args->name;
ret = pack_update_request(args, &request);
if (ret) {
ret = -1;
goto out;
}
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.update) {
ERROR("Unimplemented ops");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.update(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
goto out;
}
out:
lcrc_update_response_free(response);
return ret;
}
int cmd_update_main(int argc, const char **argv)
{
int ret = 0;
int i = 0;
struct log_config lconf = { 0 };
command_t cmd;
struct command_option options[] = {
LOG_OPTIONS(lconf),
UPDATE_OPTIONS(g_cmd_update_args),
COMMON_OPTIONS(g_cmd_update_args)
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_update_args)) {
COMMAND_ERROR("client arguments init failed\n");
exit(ECOMMON);
}
g_cmd_update_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_update_desc,
g_cmd_update_usage);
if (command_parse_args(&cmd, &g_cmd_update_args.argc, &g_cmd_update_args.argv) ||
update_checker(&g_cmd_update_args)) {
exit(EINVALIDARGS);
}
if (argc <= 3) {
COMMAND_ERROR("You must provide one or more udpate flags when using this command\n");
exit(ECOMMON);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Update: log init failed");
exit(ECOMMON);
}
if (g_cmd_update_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to update.");
exit(ECOMMON);
}
for (i = 0; i < g_cmd_update_args.argc; i++) {
g_cmd_update_args.name = g_cmd_update_args.argv[i];
if (client_update(&g_cmd_update_args)) {
ERROR("Update container \"%s\" failed\n", g_cmd_update_args.name);
ret = ECOMMON;
continue;
}
printf("%s\n", g_cmd_update_args.name);
}
return ret;
}
int update_checker(const struct client_arguments *args)
{
int ret = 0;
if (args->argc == 0) {
COMMAND_ERROR("Update requires at least 1 container names");
return EINVALIDARGS;
}
return ret;
}

View File

@ -0,0 +1,48 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container update definition
******************************************************************************/
#ifndef __CMD_UPDATE_H
#define __CMD_UPDATE_H
#include "arguments.h"
#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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "cpu-quota", 0, &(cmdargs).cr.cpu_quota, \
"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 }, \
{ CMD_OPT_TYPE_STRING, false, "cpuset-mems", 0, &(cmdargs).cr.cpuset_mems, \
"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 }, \
{ CMD_OPT_TYPE_CALLBACK, false, "memory", 'm', &(cmdargs).cr.memory_limit, \
"Memory limit", command_convert_membytes }, \
{ CMD_OPT_TYPE_CALLBACK, false, "memory-reservation", 0, &(cmdargs).cr.memory_reservation, \
"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 }, \
{ CMD_OPT_TYPE_STRING, false, "restart", 0, &(cmdargs).restart, \
"Restart policy to apply when a container exits", NULL }
extern const char g_cmd_update_desc[];
extern const char g_cmd_update_usage[];
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);
#endif /* __CMD_UPDATE_H */

View File

@ -0,0 +1,7 @@
# get current directory sources files
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} lcrc_images_srcs)
set(LCRC_IMAGES_SRCS
${lcrc_images_srcs}
PARENT_SCOPE
)

View File

@ -0,0 +1,280 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container image functions
******************************************************************************/
#include "images.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "lcrc_connect.h"
#include "log.h"
#define IMAGES_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_BOOL, false, "quiet", 'q', &((cmdargs).dispname), "Only display image names", NULL }
#define CREATED_DISPLAY_FORMAT "YYYY-MM-DD HH:MM:SS"
#define SHORT_DIGEST_LEN 12
const char g_cmd_images_desc[] = "List images";
const char g_cmd_images_usage[] = "images";
struct client_arguments g_cmd_images_args = {};
/* keep track of field widths for printing. */
struct lengths {
unsigned int ref_length;
unsigned int digest_length;
unsigned int created_length;
unsigned int size_length;
};
/* trans time */
static char *trans_time(int64_t created)
{
struct tm t;
int nret = 0;
char formated_time[sizeof(CREATED_DISPLAY_FORMAT)] = { 0 };
time_t created_time = (time_t)created;
if (!localtime_r(&created_time, &t)) {
ERROR("translate time for created failed: %s", strerror(errno));
return NULL;
}
nret = sprintf_s(formated_time, sizeof(formated_time), "%04d-%02d-%02d %02d:%02d:%02d", t.tm_year + 1900,
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
if (nret < 0) {
ERROR("format created time failed");
return NULL;
}
return util_strdup_s(formated_time);
}
/* list print table */
static void list_print_table(struct lcrc_image_info *images_list, const size_t size, const struct lengths *length)
{
const struct lcrc_image_info *in = NULL;
size_t i = 0;
char *created = NULL;
char *digest = NULL;
char *image_size = NULL;
if (length == NULL) {
return;
}
/* print header */
printf("%-*s ", (int)length->ref_length, "REF");
printf("%-*s ", (int)length->digest_length, "IMAGE ID");
printf("%-*s ", (int)length->created_length, "CREATED");
printf("%-*s ", (int)length->size_length, "SIZE");
printf("\n");
for (i = 0, in = images_list; i < size && in != NULL; i++, in++) {
printf("%-*s ", (int)length->ref_length, in->imageref ? in->imageref : "-");
digest = util_short_digest(in->digest);
printf("%-*s ", (int)length->digest_length, digest ? digest : "-");
free(digest);
created = trans_time(in->created);
printf("%-*s ", (int)length->created_length, created ? created : "-");
free(created);
image_size = util_human_size_decimal(in->size);
printf("%-*s ", (int)length->size_length, image_size ? image_size : "-");
free(image_size);
printf("\n");
}
}
/* list field width */
static void list_field_width(const struct lcrc_image_info *images_list, const size_t size, struct lengths *l)
{
const struct lcrc_image_info *in = NULL;
size_t i = 0;
char tmpbuffer[30];
for (i = 0, in = images_list; i < size && in != NULL; i++, in++) {
size_t len;
int slen;
if (in->imageref) {
len = strlen(in->imageref);
if (len > l->ref_length) {
l->ref_length = (unsigned int)len;
}
}
if (in->digest) {
len = SHORT_DIGEST_LEN;
if (len > l->digest_length) {
l->digest_length = (unsigned int)len;
}
}
if (in->created) {
len = strlen(CREATED_DISPLAY_FORMAT);
if (len > l->created_length) {
l->created_length = (unsigned int)len;
}
}
slen = sprintf_s(tmpbuffer, sizeof(tmpbuffer), "%.2f", (float)(in->size) / (1024 * 1024));
if (slen < 0) {
ERROR("sprintf tmpbuffer failed");
return;
}
if ((unsigned int)slen > l->size_length) {
l->size_length = (unsigned int)slen;
}
}
}
/*
* list all images from LCRD
*/
static void images_info_print(const struct lcrc_list_images_response *response)
{
struct lengths max_len = {
.ref_length = 30, /* ref */
.digest_length = 20, /* digest */
.created_length = 20, /* created */
.size_length = 10, /* size */
};
list_field_width(response->images_list, (size_t)response->images_num, &max_len);
list_print_table(response->images_list, (size_t)response->images_num, &max_len);
}
/* images info print quiet */
static void images_info_print_quiet(const struct lcrc_list_images_response *response)
{
struct lengths max_len = {
.ref_length = 30, /* ref */
};
const struct lcrc_image_info *in = NULL;
size_t i = 0;
for (i = 0, in = response->images_list; in != NULL && i < response->images_num; i++, in++) {
printf("%-*s ", (int)(max_len.ref_length), in->imageref ? in->imageref : "-");
printf("\n");
}
}
/*
* used by qsort function for comparing image created time
*/
static inline int lcrc_image_cmp(struct lcrc_image_info *first, struct lcrc_image_info *second)
{
if (second->created > first->created) {
return 1;
} else if (second->created < first->created) {
return -1;
} else {
return second->created_nanos > first->created_nanos;
}
}
/*
* list the images from remote
*/
static int list_images(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_list_images_request request = { 0 };
struct lcrc_list_images_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_list_images_response));
if (response == NULL) {
ERROR("Imagelist: Out of memory");
return -1;
}
ops = get_connect_client_ops();
if (ops == NULL || ops->image.list == NULL) {
ERROR("Unimplemented image list op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->image.list(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
goto out;
}
if (response->images_list != NULL && response->images_num > 0) {
qsort(response->images_list, (size_t)(response->images_num), sizeof(struct lcrc_image_info),
(int (*)(const void *, const void *))lcrc_image_cmp);
}
if (args->dispname) {
images_info_print_quiet(response);
} else {
images_info_print(response);
}
out:
lcrc_list_images_response_free(response);
return ret;
}
/* cmd images main */
int cmd_images_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
int exit_code = ECOMMON;
command_t cmd;
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_images_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_images_args.progname = argv[0];
struct command_option options[] = {
LOG_OPTIONS(lconf),
IMAGES_OPTIONS(g_cmd_images_args),
COMMON_OPTIONS(g_cmd_images_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_images_desc,
g_cmd_images_usage);
if (command_parse_args(&cmd, &g_cmd_images_args.argc, &g_cmd_images_args.argv)) {
exit(exit_code);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Images: log init failed");
exit(exit_code);
}
if (g_cmd_images_args.argc > 0) {
COMMAND_ERROR("%s: \"images\" requires 0 arguments.", g_cmd_images_args.progname);
exit(exit_code);
}
if (list_images(&g_cmd_images_args)) {
ERROR("Can not list any images");
exit(exit_code);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container images definition
******************************************************************************/
#ifndef __CMD_IMAGES_LIST_H
#define __CMD_IMAGES_LIST_H
#include "arguments.h"
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);
#endif /*__CMD_IMAGES_LIST_H*/

174
src/cmd/lcrc/images/load.c Normal file
View File

@ -0,0 +1,174 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container load functions
******************************************************************************/
#include "load.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "lcrc_connect.h"
#include "log.h"
#ifdef ENABLE_EMBEDDED_IMAGE
const char g_cmd_load_desc[] = "load an image from a manifest or a tar archive";
const char g_cmd_load_usage[] = "load [OPTIONS] --input=FILE --type=TYPE";
#else
const char g_cmd_load_desc[] = "load an image from a tar archive";
const char g_cmd_load_usage[] = "load [OPTIONS] --input=FILE";
#endif
struct client_arguments g_cmd_load_args = { 0 };
/*
* load the image from a manifest or a tar archive
*/
static int client_load_image(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_load_request request = { 0 };
struct lcrc_load_response response = { 0 };
client_connect_config_t config = { 0 };
int ret = 0;
request.file = args->file;
request.type = args->type;
request.tag = args->tag;
ops = get_connect_client_ops();
if (ops == NULL || !ops->image.load) {
ERROR("Unimplemented ops");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->image.load(&request, &response, &config);
if (ret) {
client_print_error(response.cc, response.server_errono, response.errmsg);
if (response.server_errono) {
ret = ESERVERERROR;
}
goto out;
}
out:
return ret;
}
/* Waring: This function may modify image type */
static bool valid_param()
{
if (g_cmd_load_args.argc > 0) {
COMMAND_ERROR("%s: \"load\" requires 0 arguments.", g_cmd_load_args.progname);
return false;
}
if (g_cmd_load_args.file == NULL) {
COMMAND_ERROR("missing image input, use -i,--input option");
return false;
}
if (g_cmd_load_args.type != NULL) {
if ((strcmp(g_cmd_load_args.type, "docker") != 0) &&
(strcmp(g_cmd_load_args.type, "embedded") != 0)) {
COMMAND_ERROR("Invalid image type: image type must be embedded or docker, got %s",
g_cmd_load_args.type);
return false;
}
}
#ifdef ENABLE_EMBEDDED_IMAGE
/* Treat the tar as docker archive if type is empty */
if (g_cmd_load_args.type == NULL || strncmp(g_cmd_load_args.type, "docker", 7) == 0) {
/* Docker archive tar is loaded into oci type. */
/* Do not free type here because type is not a allocated memory. */
g_cmd_load_args.type = "oci";
} else {
if (g_cmd_load_args.tag != NULL) {
COMMAND_ERROR("Option --tag can be used only when type is docker");
return false;
}
}
#else
g_cmd_load_args.type = "oci";
#endif
return true;
}
int cmd_load_main(int argc, const char **argv)
{
int ret = 0;
char file[PATH_MAX] = { 0 };
struct log_config lconf = { 0 };
int exit_code = ECOMMON;
command_t cmd;
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_load_args),
LOAD_OPTIONS(g_cmd_load_args),
#ifdef ENABLE_EMBEDDED_IMAGE
EMBEDDED_OPTIONS(g_cmd_load_args),
#endif
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_load_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_load_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_load_desc,
g_cmd_load_usage);
if (command_parse_args(&cmd, &g_cmd_load_args.argc, &g_cmd_load_args.argv)) {
exit(exit_code);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Load: log init failed");
exit(exit_code);
}
if (valid_param() != true) {
exit(exit_code);
}
/* If it's not a absolute path, add cwd to be absolute path */
if (g_cmd_load_args.file[0] != '/') {
char cwd[PATH_MAX] = { 0 };
if (!getcwd(cwd, sizeof(cwd))) {
COMMAND_ERROR("get cwd failed:%s", strerror(errno));
exit(exit_code);
}
if (sprintf_s(file, sizeof(file), "%s/%s", cwd, g_cmd_load_args.file) < 0) {
COMMAND_ERROR("filename too long");
exit(exit_code);
}
g_cmd_load_args.file = file;
}
ret = client_load_image(&g_cmd_load_args);
if (ret) {
exit(exit_code);
}
printf("Load image from \"%s\" success\n", g_cmd_load_args.file);
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,32 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container load definition
******************************************************************************/
#ifndef __CMD_LOAD_H
#define __CMD_LOAD_H
#include "arguments.h"
#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 }
#define EMBEDDED_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_STRING, false, "type", 't', &(cmdargs).type, "Image type, embedded or docker(default)", NULL }
extern const char g_cmd_load_desc[];
extern struct client_arguments g_cmd_load_args;
int cmd_load_main(int argc, const char **argv);
#endif /*__CMD_LOAD_H*/

232
src/cmd/lcrc/images/login.c Normal file
View File

@ -0,0 +1,232 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2019-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: wangfengtu
* Create: 2019-6-18
* Description: provide login
********************************************************************************/
#include "login.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "lcrc_connect.h"
#include "log.h"
const char g_cmd_login_desc[] = "Log in to a Docker registry";
const char g_cmd_login_usage[] = "login [OPTIONS] SERVER";
struct client_arguments g_cmd_login_args = {};
/*
* Login to a docker registry.
*/
int client_login(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_login_request request = { 0 };
struct lcrc_login_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_login_response));
if (response == NULL) {
ERROR("Out of memory");
return ECOMMON;
}
// Support type oci only currently.
request.type = "oci";
request.server = args->server;
request.username = args->username;
request.password = args->password;
ops = get_connect_client_ops();
if (ops == NULL || ops->image.login == NULL) {
ERROR("Unimplemented ops");
ret = ECOMMON;
goto out;
}
config = get_connect_config(args);
ret = ops->image.login(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
ret = ESERVERERROR;
goto out;
}
COMMAND_ERROR("Login Succeeded");
out:
lcrc_login_response_free(response);
return ret;
}
static int get_password_from_notty(struct client_arguments *args)
{
if (g_cmd_login_args.username == NULL && g_cmd_login_args.password_stdin) {
COMMAND_ERROR("Must provide --username with --password-stdin");
return -1;
}
if (g_cmd_login_args.password != NULL) {
printf("WARNING! Using --password via the CLI is insecure. Use --password-stdin.\n");
if (g_cmd_login_args.password_stdin) {
printf("--password and --password-stdin are mutually exclusive\n");
return -1;
}
}
// Try get password from notty input.
if (g_cmd_login_args.password_stdin) {
char password[LOGIN_PASSWORD_LEN + 1] = { 0 };
int n = util_input_notty(password, sizeof(password));
if (n == 0) {
COMMAND_ERROR("Error: Password Required");
return -1;
}
if (n < 0) {
COMMAND_ERROR("Get password from notty stdin failed: %s", strerror(errno));
return -1;
}
args->password = util_strdup_s(password);
if (memset_s(password, sizeof(password), 0, sizeof(password)) != EOK) {
ERROR("Failed to memset sensitive string memory");
}
}
return 0;
}
static int get_auth_from_terminal(struct client_arguments *args)
{
int n;
if (args->username == NULL) {
char username[LOGIN_USERNAME_LEN + 1] = {0};
printf("Username: ");
n = util_input_echo(username, sizeof(username));
if (n == 0) {
ERROR("Error: Non-null Username Required\n");
return -1;
}
if (n < 0) {
if (errno == ENOTTY) {
COMMAND_ERROR("Error: Cannot perform an interactive login from a non TTY device");
return -1;
}
COMMAND_ERROR("Get username failed: %s", strerror(errno));
return -1;
}
args->username = util_strdup_s(username);
}
if (args->password == NULL) {
char password[LOGIN_PASSWORD_LEN + 1] = {0};
printf("Password: ");
n = util_input_noecho(password, sizeof(password));
if (n == 0) {
ERROR("Error: Password Required\n");
return -1;
}
if (n < 0) {
if (errno == ENOTTY) {
COMMAND_ERROR("Error: Cannot perform an interactive login from a non TTY device");
return -1;
}
COMMAND_ERROR("Get password failed: %s", strerror(errno));
return -1;
}
args->password = util_strdup_s(password);
if (memset_s(password, sizeof(password), 0, sizeof(password)) != EOK) {
ERROR("Failed to memset sensitive string memory");
}
}
return 0;
}
static int get_auth(struct client_arguments *args)
{
// Try get password from notty input.
if (get_password_from_notty(&g_cmd_login_args)) {
return -1;
}
// Try get username and password from terminal.
if (get_auth_from_terminal(&g_cmd_login_args)) {
return -1;
}
if (args->username == NULL || args->password == NULL) {
// This should not happen.
COMMAND_ERROR("Missing username or password");
return -1;
}
return 0;
}
int cmd_login_main(int argc, const char **argv)
{
int ret = 0;
struct log_config lconf = { 0 };
int exit_code = 1; /* exit 1 if failed to login */
command_t cmd;
struct command_option options[] = {
COMMON_OPTIONS(g_cmd_login_args),
LOGIN_OPTIONS(g_cmd_login_args)
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_login_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_login_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_login_desc,
g_cmd_login_usage);
if (command_parse_args(&cmd, &g_cmd_login_args.argc, &g_cmd_login_args.argv)) {
exit(exit_code);
}
if (log_init(&lconf)) {
COMMAND_ERROR("login: log init failed");
exit(exit_code);
}
if (g_cmd_login_args.argc != 1) {
COMMAND_ERROR("login requires 1 argument.");
exit(exit_code);
}
g_cmd_login_args.server = g_cmd_login_args.argv[0];
ret = get_auth(&g_cmd_login_args);
if (ret != 0) {
exit(exit_code);
}
ret = client_login(&g_cmd_login_args);
if (ret != 0) {
exit(exit_code);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,31 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: wangfengtu
* Description: provide login definition
******************************************************************************/
#ifndef __CMD_LOGIN_H
#define __CMD_LOGIN_H
#include "arguments.h"
#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 }, \
extern const char g_cmd_login_desc[];
extern const char g_cmd_login_usage[];
extern struct client_arguments g_cmd_login_args;
int cmd_login_main(int argc, const char **argv);
#endif /*__CMD_LOGIN_H*/

View File

@ -0,0 +1,115 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2019-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: wangfengtu
* Create: 2019-6-18
* Description: provide logout
********************************************************************************/
#include "logout.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "lcrc_connect.h"
#include "log.h"
const char g_cmd_logout_desc[] = "Log out from a Docker registry";
const char g_cmd_logout_usage[] = "logout SERVER";
struct client_arguments g_cmd_logout_args = {};
/*
* Logout from a docker registry.
*/
int client_logout(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_logout_request request = { 0 };
struct lcrc_logout_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_logout_response));
if (response == NULL) {
ERROR("Out of memory");
return ECOMMON;
}
// Support type oci only currently.
request.type = "oci";
request.server = args->server;
ops = get_connect_client_ops();
if (ops == NULL || ops->image.logout == NULL) {
ERROR("Unimplemented ops");
ret = ECOMMON;
goto out;
}
config = get_connect_config(args);
ret = ops->image.logout(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
ret = ESERVERERROR;
goto out;
}
COMMAND_ERROR("Logout Succeeded");
out:
lcrc_logout_response_free(response);
return ret;
}
int cmd_logout_main(int argc, const char **argv)
{
int ret = 0;
struct log_config lconf = { 0 };
int exit_code = 1; /* exit 1 if failed to logout */
command_t cmd;
struct command_option options[] = { COMMON_OPTIONS(g_cmd_logout_args) };
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_logout_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_logout_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_logout_desc,
g_cmd_logout_usage);
if (command_parse_args(&cmd, &g_cmd_logout_args.argc, &g_cmd_logout_args.argv)) {
exit(exit_code);
}
if (log_init(&lconf)) {
COMMAND_ERROR("logout: log init failed");
exit(exit_code);
}
if (g_cmd_logout_args.argc != 1) {
COMMAND_ERROR("logout requires 1 argument.");
exit(exit_code);
}
g_cmd_logout_args.server = g_cmd_logout_args.argv[0];
ret = client_logout(&g_cmd_logout_args);
if (ret != 0) {
exit(exit_code);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,24 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: wangfengtu
* Description: provide logout definition
******************************************************************************/
#ifndef __CMD_LOGOUT_H
#define __CMD_LOGOUT_H
#include "arguments.h"
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);
#endif /*__CMD_LOGOUT_H*/

114
src/cmd/lcrc/images/pull.c Normal file
View File

@ -0,0 +1,114 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2019-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: lifeng
* Create: 2019-3-29
* Description: provide pull image
********************************************************************************/
#include "pull.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "lcrc_connect.h"
#include "log.h"
const char g_cmd_pull_desc[] = "Pull an image or a repository from a registry";
const char g_cmd_pull_usage[] = "pull [OPTIONS] NAME[:TAG|@DIGEST]";
struct client_arguments g_cmd_pull_args = {};
/*
* Pull an image or a repository from a registry
*/
int client_pull(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_pull_request request = { 0 };
struct lcrc_pull_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_pull_response));
if (response == NULL) {
ERROR("Out of memory");
return ECOMMON;
}
request.image_name = args->image_name;
ops = get_connect_client_ops();
if (ops == NULL || ops->image.pull == NULL) {
ERROR("Unimplemented ops");
ret = ECOMMON;
goto out;
}
COMMAND_ERROR("Image \"%s\" pulling", request.image_name);
config = get_connect_config(args);
ret = ops->image.pull(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
ret = ESERVERERROR;
goto out;
}
COMMAND_ERROR("Image \"%s\" pulled", response->image_ref);
out:
lcrc_pull_response_free(response);
return ret;
}
int cmd_pull_main(int argc, const char **argv)
{
int ret = 0;
struct log_config lconf = { 0 };
int exit_code = 1; /* exit 1 if failed to pull */
command_t cmd;
struct command_option options[] = { COMMON_OPTIONS(g_cmd_pull_args) };
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_pull_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_pull_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_pull_desc,
g_cmd_pull_usage);
if (command_parse_args(&cmd, &g_cmd_pull_args.argc, &g_cmd_pull_args.argv)) {
exit(exit_code);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Pull: log init failed");
exit(exit_code);
}
if (g_cmd_pull_args.argc != 1) {
COMMAND_ERROR("pull requires 1 argument.");
exit(exit_code);
}
g_cmd_pull_args.image_name = g_cmd_pull_args.argv[0];
ret = client_pull(&g_cmd_pull_args);
if (ret != 0) {
exit(exit_code);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,28 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2019-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: lifeng
* Create: 2019-3-29
* Description: provide pull image
********************************************************************************/
#ifndef __CMD_PULL_IMAGE_H
#define __CMD_PULL_IMAGE_H
#include "arguments.h"
extern const char g_cmd_pull_desc[];
extern const char g_cmd_pull_usage[];
extern struct client_arguments g_cmd_pull_args;
int client_pull(const struct client_arguments *args);
int cmd_pull_main(int argc, const char **argv);
#endif /*__CMD_PULL_IMAGE_H*/

132
src/cmd/lcrc/images/rmi.c Normal file
View File

@ -0,0 +1,132 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container remove functions
******************************************************************************/
#include "rmi.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "lcrc_connect.h"
#include "log.h"
const char g_cmd_rmi_desc[] = "Remove one or more images";
const char g_cmd_rmi_usage[] = "rmi [OPTIONS] IMAGE [IMAGE...]";
struct client_arguments g_cmd_rmi_args = { .force = false };
/*
* remove a image from DB
*/
static int client_rmi(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_rmi_request request = { 0 };
struct lcrc_rmi_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
if (strcmp(args->image_name, "none") == 0 || strcmp(args->image_name, "none:latest") == 0) {
COMMAND_ERROR("Can not remove image '%s', image name 'none' or 'none:latest' is reserved", args->image_name);
return -1;
}
response = util_common_calloc_s(sizeof(struct lcrc_rmi_response));
if (response == NULL) {
ERROR("Out of memory");
return -1;
}
request.image_name = args->image_name;
request.force = args->force;
ops = get_connect_client_ops();
if (ops == NULL || !ops->image.remove) {
ERROR("Unimplemented ops");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->image.remove(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
if (response->server_errono) {
ret = ESERVERERROR;
}
goto out;
}
out:
lcrc_rmi_response_free(response);
return ret;
}
int cmd_rmi_main(int argc, const char **argv)
{
int i = 0;
int err = 0;
struct log_config lconf = { 0 };
int exit_code = 1; /* exit 1 if remove failed because docker return 1 */
command_t cmd;
struct command_option options[] = {
LOG_OPTIONS(lconf),
COMMON_OPTIONS(g_cmd_rmi_args),
RMI_OPTIONS(g_cmd_rmi_args)
};
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_rmi_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_rmi_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_rmi_desc,
g_cmd_rmi_usage);
if (command_parse_args(&cmd, &g_cmd_rmi_args.argc, &g_cmd_rmi_args.argv)) {
exit(exit_code);
}
if (log_init(&lconf)) {
COMMAND_ERROR("RMI: log init failed");
exit(exit_code);
}
if (g_cmd_rmi_args.argc == 0) {
COMMAND_ERROR("\"rmi\" requires at least 1 image names");
exit(exit_code);
}
if (g_cmd_rmi_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many images to remove.");
exit(exit_code);
}
for (i = 0; i < g_cmd_rmi_args.argc; i++) {
g_cmd_rmi_args.image_name = g_cmd_rmi_args.argv[i];
int ret = client_rmi(&g_cmd_rmi_args);
if (ret != 0) {
ERROR("Image \"%s\" remove failed", g_cmd_rmi_args.image_name);
err = ret;
continue;
}
printf("Image \"%s\" removed\n", g_cmd_rmi_args.image_name);
}
if (err) {
exit(exit_code);
}
exit(EXIT_SUCCESS);
}

28
src/cmd/lcrc/images/rmi.h Normal file
View File

@ -0,0 +1,28 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container remove definition
******************************************************************************/
#ifndef __CMD_REMOVE_IMAGE_H
#define __CMD_REMOVE_IMAGE_H
#include "arguments.h"
#define RMI_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_BOOL, false, "force", 'f', &(cmdargs).force, "Force removal of the image", NULL }
extern const char g_cmd_rmi_desc[];
extern const char g_cmd_rmi_usage[];
extern struct client_arguments g_cmd_rmi_args;
int cmd_rmi_main(int argc, const char **argv);
#endif /*__CMD_REMOVE_IMAGE_H*/

View File

@ -0,0 +1,7 @@
# get current directory sources files
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} lcrc_information_srcs)
set(LCRC_INFORMATION_SRCS
${lcrc_information_srcs}
PARENT_SCOPE
)

View File

@ -0,0 +1,103 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container health functions
******************************************************************************/
#include "health.h"
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_health_check_desc[] = "LCRD health check";
const char g_cmd_health_check_usage[] = "health [command options]";
struct client_arguments g_cmd_health_check_args = {
.service = NULL,
};
/*
* Create a health check request message and call RPC
*/
static int client_health_check(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_health_check_request request = { 0 };
struct lcrc_health_check_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_health_check_response));
if (response == NULL) {
ERROR("Health: Out of memory");
return -1;
}
request.service = args->service;
ops = get_connect_client_ops();
if (ops == NULL || !ops->health.check) {
ERROR("Unimplemented health op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->health.check(&request, response, &config);
if (ret || response->health_status != HEALTH_SERVING_STATUS_SERVING) {
ret = -1;
}
out:
lcrc_health_check_response_free(response);
return ret;
}
int cmd_health_check_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
lconf.name = argv[0];
lconf.priority = "ERROR";
lconf.file = NULL;
lconf.quiet = true;
lconf.driver = "stdout";
if (log_init(&lconf)) {
COMMAND_ERROR("Health: log init failed");
exit(ECOMMON);
}
command_t cmd;
if (client_arguments_init(&g_cmd_health_check_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_health_check_args.progname = argv[0];
struct command_option options[] = {
HEALTH_OPTIONS(g_cmd_health_check_args),
COMMON_OPTIONS(g_cmd_health_check_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv,
g_cmd_health_check_desc, g_cmd_health_check_usage);
if (command_parse_args(&cmd, &g_cmd_health_check_args.argc, &g_cmd_health_check_args.argv)) {
exit(EINVALIDARGS);
}
if (client_health_check(&g_cmd_health_check_args)) {
printf("LCRD with socket name '%s' is NOT SERVING\n", g_cmd_health_check_args.socket);
exit(ECOMMON);
}
printf("LCRD with socket name '%s' is SERVING\n", g_cmd_health_check_args.socket);
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,28 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container health definition
******************************************************************************/
#ifndef __CMD_HEALTHCHECK_H
#define __CMD_HEALTHCHECK_H
#include "arguments.h"
#define HEALTH_OPTIONS(cmdargs) \
{ CMD_OPT_TYPE_STRING, false, "service", 'S', &(cmdargs).service, "GRPC service name", NULL }
extern const char g_cmd_health_check_desc[];
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);
#endif

View File

@ -0,0 +1,150 @@
/******************************************************************************
* 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: maoweiyong
* Create: 2018-11-08
* Description: provide container info functions
******************************************************************************/
#include "info.h"
#include <stdio.h>
#include <stdlib.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "log.h"
#include "config.h"
#include "lcrc_connect.h"
const char g_cmd_info_desc[] = "Display system-wide information";
const char g_cmd_info_usage[] = "info";
struct client_arguments g_cmd_info_args = {};
static void client_info_server(const struct lcrc_info_response *response)
{
printf("Containers: %u\n", (unsigned int)(response->containers_num));
printf(" Running: %u\n", (unsigned int)(response->c_running));
printf(" Paused: %u\n", (unsigned int)(response->c_paused));
printf(" Stopped: %u\n", (unsigned int)(response->c_stopped));
printf("Images: %u\n", (unsigned int)(response->images_num));
if (response->version != NULL) {
printf("Server Version: %s\n", response->version);
}
if (response->logging_driver != NULL) {
printf("Logging Driver: %s\n", response->logging_driver);
}
if (response->cgroup_driver != NULL) {
printf("Cgroup Driverr: %s\n", response->cgroup_driver);
}
if (response->huge_page_size != NULL) {
printf("Hugetlb Pagesize: %s\n", response->huge_page_size);
}
if (response->kversion != NULL) {
printf("Kernel Version: %s\n", response->kversion);
}
if (response->operating_system != NULL) {
printf("Operating System: %s\n", response->operating_system);
}
if (response->os_type != NULL) {
printf("OSType: %s\n", response->os_type);
}
if (response->architecture != NULL) {
printf("Architecture: %s\n", response->architecture);
}
printf("CPUs: %u\n", (unsigned int)(response->cpus));
printf("Total Memory: %u GB\n", (unsigned int)(response->total_mem));
if (response->nodename != NULL) {
printf("Name: %s\n", response->nodename);
}
if (response->isulad_root_dir != NULL) {
printf("iSulad Root Dir: %s\n", response->isulad_root_dir);
}
if (response->http_proxy != NULL) {
printf("Http Proxy: %s\n", response->http_proxy);
}
if (response->https_proxy != NULL) {
printf("Https Proxy: %s\n", response->https_proxy);
}
if (response->no_proxy != NULL) {
printf("No Proxy: %s\n", response->no_proxy);
}
}
static int client_info(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_info_request request = { 0 };
struct lcrc_info_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_info_response));
if (response == NULL) {
ERROR("Info: Out of memory");
return -1;
}
ops = get_connect_client_ops();
if (ops == NULL || (ops->container.info) == NULL) {
ERROR("Unimplemented info op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.info(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
goto out;
}
client_info_server(response);
out:
lcrc_info_response_free(response);
return ret;
}
int cmd_info_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
command_t cmd;
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_info_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_info_args.progname = argv[0];
struct command_option options[] = { LOG_OPTIONS(lconf), COMMON_OPTIONS(g_cmd_info_args) };
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_info_desc,
g_cmd_info_usage);
if (command_parse_args(&cmd, &g_cmd_info_args.argc, &g_cmd_info_args.argv) != 0) {
exit(EINVALIDARGS);
}
if (log_init(&lconf) != 0) {
COMMAND_ERROR("Info: log init failed");
exit(ECOMMON);
}
if (g_cmd_info_args.argc > 0) {
COMMAND_ERROR("%s: \"info\" requires 0 arguments.", g_cmd_info_args.progname);
exit(ECOMMON);
}
if (client_info(&g_cmd_info_args) != 0) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* 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: maoweiyong
* Create: 2018-11-08
* Description: provide container info definition
******************************************************************************/
#ifndef __CMD_INFO_H
#define __CMD_INFO_H
#include "arguments.h"
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);
#endif /* __CMD_INFO_H */

View File

@ -0,0 +1,814 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container inspect functions
******************************************************************************/
#include "error.h"
#include "inspect.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
#include "console.h"
#include "utils.h"
#include "securec.h"
#include "json_common.h"
#include <regex.h>
const char g_cmd_inspect_desc[] = "Return low-level information on a container or image";
const char g_cmd_inspect_usage[] = "inspect [options] CONTAINER|IMAGE [CONTAINER|IMAGE...]";
struct client_arguments g_cmd_inspect_args = {
.format = NULL,
.time = 120, // timeout time
};
#define PRINTF_TAB_LEN 4
#define TOP_LEVEL_OBJ 0x10
#define IS_TOP_LEVEL_OBJ(value) ((value)&TOP_LEVEL_OBJ)
#define LAST_ELEMENT_BIT 0x0F
#define NOT_LAST_ELEMENT 0x00
#define LAST_ELEMENT 0x01
#define IS_LAST_ELEMENT(value) (LAST_ELEMENT == ((value)&LAST_ELEMENT_BIT))
#define YAJL_TYPEOF(json) ((json)->type)
#define CONTAINER_INSPECT_ERR (-1)
#define CONTAINER_NOT_FOUND (-2)
typedef struct {
yajl_val tree_root; /* Should be free by yajl_tree_free() */
yajl_val tree_print; /* Point to the object be printf */
} container_tree_t;
static yajl_val inspect_get_json_info(yajl_val element, char *key_string);
static void print_json_aux(yajl_val element, int indent, int flags);
/*
* Parse text into a JSON tree. If text is valid JSON, returns a
* yajl_val structure, otherwise prints and error and returns null.
* Note: return tree need free by function yajl_tree_free (tree).
*/
#define ERR_BUF 1024
static yajl_val inspect_load_json(const char *json_data)
{
yajl_val tree = NULL;
char errbuf[ERR_BUF];
tree = yajl_tree_parse(json_data, errbuf, sizeof(errbuf));
if (tree == NULL) {
ERROR("Parse json data failed %s\n", errbuf);
return NULL;
}
return tree;
}
static yajl_val json_get_val(yajl_val tree, const char *name, yajl_type type)
{
const char *path[] = { name, NULL };
return yajl_tree_get(tree, path, type);
}
static yajl_val json_object(yajl_val element, char *key)
{
yajl_val node = NULL;
char *top_key = key;
char *next_context = NULL;
top_key = strtok_s(top_key, ".", &next_context);
if (top_key == NULL) {
return NULL;
}
node = json_get_val(element, top_key, yajl_t_any);
if (node) {
node = inspect_get_json_info(node, next_context);
}
return node;
}
static yajl_val json_array(yajl_val element, char *key)
{
if (element == NULL || key == NULL) {
return NULL;
}
size_t i = 0;
size_t size = 0;
yajl_val node = NULL;
yajl_val value = NULL;
char *top_key = key;
char *next_context = NULL;
if (YAJL_GET_ARRAY(element) != NULL) {
size = YAJL_GET_ARRAY(element)->len;
}
top_key = strtok_s(top_key, ".", &next_context);
if (top_key == NULL) {
return NULL;
}
for (i = 0; i < size; i++) {
value = element->u.array.values[i];
node = json_get_val(value, top_key, yajl_t_any);
if (node) {
node = inspect_get_json_info(node, next_context);
if (node) {
break;
}
}
}
return node;
}
static yajl_val inspect_get_json_info(yajl_val element, char *key_string)
{
yajl_val node = NULL;
if (element == NULL) {
return NULL;
}
/* If "key_string" equal to NULL, return the input element. */
if ((key_string == NULL) || (strlen(key_string) == 0)) {
return element;
}
switch (YAJL_TYPEOF(element)) {
case yajl_t_object:
node = json_object(element, key_string);
break;
case yajl_t_array:
node = json_array(element, key_string);
break;
case yajl_t_any:
case yajl_t_null:
case yajl_t_false:
case yajl_t_true:
case yajl_t_number:
case yajl_t_string:
default:
ERROR("unrecognized JSON type %d\n", YAJL_TYPEOF(element));
break;
}
return node;
}
static bool inspect_filter_done(yajl_val root, const char *filter, container_tree_t *tree_array)
{
yajl_val object = root;
char *key_string = NULL;
if (filter != NULL) {
key_string = util_strdup_s(filter);
object = inspect_get_json_info(root, key_string);
if (object == NULL) {
COMMAND_ERROR("Executing \"\" at <.%s>: map has no entry for key \"%s\"", filter, key_string);
free(key_string);
return false;
}
free(key_string);
}
tree_array->tree_print = object;
return true;
}
/*
* RETURN VALUE:
* 0: inspect container success
* CONTAINER_INSPECT_ERR: have the container, but failed to inspect due to other reasons
* CONTAINER_NOT_FOUND: no such container
*/
static int client_inspect_container(const struct lcrc_inspect_request *request, struct lcrc_inspect_response *response,
client_connect_config_t *config, const lcrc_connect_ops *ops)
{
int ret = 0;
ret = ops->container.inspect(request, response, config);
if (ret != 0) {
if ((strstr(response->errmsg, "Inspect invalid name") != NULL) ||
(strstr(response->errmsg, "No such image or container or accelerator") != NULL)) {
return CONTAINER_NOT_FOUND;
}
/* have the container, but failed to inspect due to other reasons */
client_print_error(response->cc, response->server_errono, response->errmsg);
ret = CONTAINER_INSPECT_ERR;
}
return ret;
}
static int client_inspect_image(const struct lcrc_inspect_request *request, struct lcrc_inspect_response *response,
client_connect_config_t *config, const lcrc_connect_ops *ops)
{
int ret = 0;
ret = ops->image.inspect(request, response, config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
return ret;
}
/*
* Create a inspect request message and call RPC
*/
static int client_inspect(const struct client_arguments *args, const char *filter, container_tree_t *tree_array)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_inspect_request request = { 0 };
struct lcrc_inspect_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
yajl_val tree = NULL;
response = util_common_calloc_s(sizeof(struct lcrc_inspect_response));
if (response == NULL) {
ERROR("Out of memory");
ret = -1;
goto out;
}
request.name = args->name;
request.bformat = args->format ? true : false;
request.timeout = args->time;
ops = get_connect_client_ops();
if (ops == NULL || ops->container.inspect == NULL || ops->image.inspect == NULL) {
ERROR("Unimplemented ops");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = client_inspect_container(&request, response, &config, ops);
if (ret == CONTAINER_NOT_FOUND) {
lcrc_inspect_response_free(response);
response = NULL;
response = util_common_calloc_s(sizeof(struct lcrc_inspect_response));
if (response == NULL) {
ERROR("Out of memory");
ret = -1;
goto out;
}
ret = client_inspect_image(&request, response, &config, ops);
}
if (ret != 0) {
goto out;
}
if (response == NULL || response->json == NULL) {
ERROR("Container or image json is empty");
ret = -1;
goto out;
}
tree = inspect_load_json(response->json);
if (tree == NULL) {
ret = -1;
goto out;
}
if (!inspect_filter_done(tree, filter, tree_array)) {
ret = -1;
yajl_tree_free(tree);
goto out;
}
tree_array->tree_root = tree;
out:
lcrc_inspect_response_free(response);
return ret;
}
static void print_json_string(yajl_val element, int flags)
{
const char *str = YAJL_GET_STRING(element);
const char *hexchars = "0123456789ABCDEF";
char hex[7] = { '\\', 'u', '0', '0', '\0', '\0', '\0' };
putchar('"');
if (str == NULL) {
goto out;
}
for (; *str != '\0'; str++) {
const char *escapestr = NULL;
switch (*str) {
case '\r':
escapestr = "\\r";
break;
case '\n':
escapestr = "\\n";
break;
case '\\':
escapestr = "\\\\";
break;
case '"':
escapestr = "\\\"";
break;
case '\f':
escapestr = "\\f";
break;
case '\b':
escapestr = "\\b";
break;
case '\t':
escapestr = "\\t";
break;
default:
if ((unsigned char)(*str) < 0x20) {
hex[4] = hexchars[(unsigned char)(*str) >> 4];
hex[5] = hexchars[(unsigned char)(*str) & 0x0F];
escapestr = hex;
}
break;
}
if (escapestr != NULL) {
printf("%s", escapestr);
} else {
putchar(*str);
}
}
out:
putchar('"');
if (!IS_LAST_ELEMENT((unsigned int)flags)) {
putchar(',');
}
}
static void print_json_number(yajl_val element, int flags)
{
if (IS_LAST_ELEMENT((unsigned int)flags)) {
printf("%s", YAJL_GET_NUMBER(element));
} else {
printf("%s,", YAJL_GET_NUMBER(element));
}
}
static void print_json_true(int flags)
{
if (IS_LAST_ELEMENT((unsigned int)flags)) {
printf("true");
} else {
printf("true,");
}
}
static void print_json_false(int flags)
{
if (IS_LAST_ELEMENT((unsigned int)flags)) {
printf("false");
} else {
printf("false,");
}
}
static void print_json_null(int flags)
{
if (IS_LAST_ELEMENT((unsigned int)flags)) {
printf("null");
} else {
printf("null,");
}
}
static void print_json_indent(int indent, bool new_line)
{
int i = 0;
if (new_line) {
printf("\n");
}
for (i = 0; i < indent; i++) {
putchar(' ');
}
}
static void print_json_object(yajl_val element, int indent, int flags)
{
size_t size = 0;
const char *objkey = NULL;
yajl_val value = NULL;
size_t i = 0;
if (element == NULL) {
return;
}
if (YAJL_GET_OBJECT(element) != NULL) {
size = YAJL_GET_OBJECT(element)->len;
}
if (IS_TOP_LEVEL_OBJ((unsigned int)flags)) {
print_json_indent(indent, false);
}
if (size == 0) {
if (IS_LAST_ELEMENT((unsigned int)flags)) {
printf("{}");
} else {
printf("{},");
}
return;
}
printf("{");
for (i = 0; i < size; i++) {
print_json_indent(indent + PRINTF_TAB_LEN, true);
objkey = element->u.object.keys[i];
value = element->u.object.values[i];
printf("\"%s\": ", objkey);
if ((i + 1) == size) {
print_json_aux(value, indent + PRINTF_TAB_LEN, LAST_ELEMENT);
} else {
print_json_aux(value, indent + PRINTF_TAB_LEN, NOT_LAST_ELEMENT);
}
}
print_json_indent(indent, true);
if (IS_LAST_ELEMENT((unsigned int)flags)) {
printf("}");
} else {
printf("},");
}
}
static void print_json_array(yajl_val element, int indent, int flags)
{
size_t i = 0;
size_t size = 0;
yajl_val value = NULL;
if (element == NULL) {
return;
}
if (YAJL_GET_ARRAY(element) != NULL) {
size = YAJL_GET_ARRAY(element)->len;
}
if (IS_TOP_LEVEL_OBJ((unsigned int)flags)) {
print_json_indent(indent, false);
}
if (size == 0) {
if (IS_LAST_ELEMENT((unsigned int)flags)) {
printf("[]");
} else {
printf("[],");
}
return;
}
printf("[");
for (i = 0; i < size; i++) {
print_json_indent(indent + PRINTF_TAB_LEN, true);
value = element->u.array.values[i];
if ((i + 1) == size) {
print_json_aux(value, indent + PRINTF_TAB_LEN, LAST_ELEMENT);
} else {
print_json_aux(value, indent + PRINTF_TAB_LEN, NOT_LAST_ELEMENT);
}
}
print_json_indent(indent, true);
if (IS_LAST_ELEMENT((unsigned int)flags)) {
printf("]");
} else {
printf("],");
}
}
static void print_json_aux(yajl_val element, int indent, int flags)
{
if (element == NULL) {
return;
}
switch (YAJL_TYPEOF(element)) {
case yajl_t_object:
print_json_object(element, indent, flags);
break;
case yajl_t_array:
print_json_array(element, indent, flags);
break;
case yajl_t_string:
print_json_string(element, flags);
break;
case yajl_t_number:
print_json_number(element, flags);
break;
case yajl_t_true:
print_json_true(flags);
break;
case yajl_t_false:
print_json_false(flags);
break;
case yajl_t_null:
print_json_null(flags);
break;
case yajl_t_any:
default:
ERROR("unrecognized JSON type %d\n", YAJL_TYPEOF(element));
break;
}
}
/*
* Print yajl tree as JSON format.
*/
static void print_json(yajl_val tree, int indent)
{
if (tree == NULL) {
return;
}
print_json_aux(tree, indent, LAST_ELEMENT | TOP_LEVEL_OBJ);
}
static void inspect_show_result(int show_nums, const container_tree_t *tree_array, const char *format)
{
int i = 0;
yajl_val tree = NULL;
int indent = 0;
if (show_nums == 0) {
if (format == NULL) {
printf("[]\n");
}
return;
}
if (format == NULL) {
printf("[\n");
indent = PRINTF_TAB_LEN;
}
for (i = 0; i < show_nums; i++) {
tree = tree_array[i].tree_print;
print_json(tree, indent);
if ((i + 1) != show_nums) {
if (format == NULL) {
printf(",\n");
} else {
printf("\n");
}
}
}
if (format == NULL) {
printf("\n]\n");
} else {
printf("\n");
}
}
static void inspect_free_trees(int tree_nums, container_tree_t *tree_array)
{
int i = 0;
for (i = 0; i < tree_nums; i++) {
if (tree_array[i].tree_root) {
yajl_tree_free(tree_array[i].tree_root);
tree_array[i].tree_root = NULL;
tree_array[i].tree_print = NULL;
}
}
}
/* arg string format: "{{json .State.Running}}"
* ret_string should be free outside by free().
*/
static char *inspect_pause_filter(const char *arg)
{
char *input_str = NULL;
char *p = NULL;
char *ret_string = NULL;
char *next_context = NULL;
input_str = util_strdup_s(arg);
p = strtok_s(input_str, ".", &next_context);
if (p == NULL) {
goto out;
}
p = next_context;
if (p == NULL) {
goto out;
}
p = strtok_s(p, " }", &next_context);
if (p == NULL) {
goto out;
}
ret_string = util_strdup_s(p);
out:
if (input_str != NULL) {
free(input_str);
}
return ret_string;
}
#define MATCH_NUM 1
#define CHECK_FAILED (-1)
#define JSON_ARGS "^\\s*\\{\\s*\\{\\s*json\\s+[^\\s]+\\s*.*\\}\\s*\\}\\s*$"
static int inspect_check(const char *json_str, const char *regex)
{
int status = 0;
regmatch_t pmatch[MATCH_NUM] = { { 0 } };
regex_t reg;
if (json_str == NULL) {
ERROR("Filter string is NULL.");
return CHECK_FAILED;
}
regcomp(&reg, regex, REG_EXTENDED);
status = regexec(&reg, json_str, MATCH_NUM, pmatch, 0);
regfree(&reg);
if (status != 0) {
/* Log by caller */
return CHECK_FAILED;
}
return 0;
}
static int inspect_check_format_f(const char *json_str)
{
int ret = 0;
if (json_str == NULL) {
ERROR("Filter string is NULL.");
return CHECK_FAILED;
}
/* check "{{json .xxx.xxx}}" */
ret = inspect_check(json_str, "^\\s*\\{\\s*\\{\\s*json\\s+(\\.\\w+)+\\s*\\}\\s*\\}\\s*$");
if (ret == 0) {
return 0;
}
/* check "{{ ... }}" */
ret = inspect_check(json_str, "^\\s*\\{\\s*\\{\\s*[^{}]*\\s*\\}\\s*\\}\\s*$");
if (ret != 0) {
COMMAND_ERROR("Unexpected \"{\" or \"}\" in operand, should be \"{{ ... }}\".");
goto out;
}
/* json args. */
ret = inspect_check(json_str, "^\\s*\\{\\s*\\{\\s*json\\s*\\}\\s*\\}\\s*$");
if (ret == 0) {
COMMAND_ERROR("Executing \"\" at <json>: wrong number of args for json: want 1 got 0.");
goto out;
}
/* check "{{json... }}" */
ret = inspect_check(json_str, "^\\s*\\{\\s*\\{\\s*json\\W.*\\s*\\}\\s*\\}\\s*$");
if (ret != 0) {
COMMAND_ERROR("Output mode error,"
"support function \"json\" only. E.g \"{{json ... }}\" is right.");
goto out;
}
/* json args. */
ret = inspect_check(json_str, JSON_ARGS);
if (ret != 0) {
COMMAND_ERROR("Executing \"\" at <json>: wrong number of args for json: want 1 got 0.");
goto out;
}
/* "{{json .xxx.xxx }}" check failed log */
COMMAND_ERROR("Unexpected <.> in operand. E.g \"{{json .xxx.xxx }}\" is right.");
out:
return CHECK_FAILED;
}
int cmd_inspect_main(int argc, const char **argv)
{
int i = 0;
int status = 0;
struct log_config lconf = { 0 };
int success_counts = 0;
char *filter_string = NULL;
container_tree_t *tree_array = NULL;
size_t array_size = 0;
command_t cmd;
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_inspect_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_inspect_args.progname = argv[0];
struct command_option options[] = {
LOG_OPTIONS(lconf),
INSPECT_OPTIONS(g_cmd_inspect_args),
COMMON_OPTIONS(g_cmd_inspect_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_inspect_desc,
g_cmd_inspect_usage);
if (command_parse_args(&cmd, &g_cmd_inspect_args.argc, &g_cmd_inspect_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("log init failed");
exit(ECOMMON);
}
if (g_cmd_inspect_args.argc == 0) {
COMMAND_ERROR("\"inspect\" requires a minimum of 1 argument.");
exit(EINVALIDARGS);
}
if (g_cmd_inspect_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many arguments.");
exit(EINVALIDARGS);
}
if ((size_t)g_cmd_inspect_args.argc > SIZE_MAX / sizeof(container_tree_t) - 1) {
COMMAND_ERROR("The number of parameters of inspect is too large");
exit(ECOMMON);
}
array_size = sizeof(container_tree_t) * (size_t)(g_cmd_inspect_args.argc + 1);
tree_array = (container_tree_t *)util_common_calloc_s(array_size);
if (tree_array == NULL) {
ERROR("Malloc failed\n");
exit(ECOMMON);
}
if (g_cmd_inspect_args.format != NULL) {
int ret;
ret = inspect_check_format_f(g_cmd_inspect_args.format);
if (ret != 0) {
free(tree_array);
tree_array = NULL;
exit(ECOMMON);
}
filter_string = inspect_pause_filter(g_cmd_inspect_args.format);
if (filter_string == NULL) {
COMMAND_ERROR("Inspect format parameter invalid: %s", g_cmd_inspect_args.format);
free(tree_array);
tree_array = NULL;
exit(EINVALIDARGS);
}
}
for (i = 0; i < g_cmd_inspect_args.argc; i++) {
g_cmd_inspect_args.name = g_cmd_inspect_args.argv[i];
if (client_inspect(&g_cmd_inspect_args, filter_string, &tree_array[i])) {
status = -1;
break;
}
success_counts++;
}
if (tree_array != NULL) {
inspect_show_result(success_counts, tree_array, g_cmd_inspect_args.format);
inspect_free_trees(success_counts, tree_array);
}
free(tree_array);
free(filter_string);
if (status) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,31 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container inspect definition
******************************************************************************/
#ifndef __CMD_INSPECT_H
#define __CMD_INSPECT_H
#include "arguments.h"
#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 }
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);
#endif /* __CMD_INSPECT_H */

View File

@ -0,0 +1,152 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container logs functions
******************************************************************************/
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <limits.h>
#include <errno.h>
#include "error.h"
#include "securec.h"
#include "logs.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_logs_desc[] = "Fetch the logs of a container";
const char g_cmd_logs_usage[] = "logs [OPTIONS] CONTAINER";
struct client_arguments g_cmd_logs_args = {
.follow = false,
.tail = -1,
};
static int do_logs(const struct client_arguments *args)
{
#define DISABLE_ERR_MESSAGE "disable console log"
lcrc_connect_ops *ops = NULL;
struct lcrc_logs_request *request = NULL;
struct lcrc_logs_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_container_conf_response));
if (response == NULL) {
ERROR("Log: Out of memory");
return -1;
}
request = util_common_calloc_s(sizeof(struct lcrc_logs_request));
if (request == NULL) {
ERROR("Out of memory");
ret = -1;
goto out;
}
ops = get_connect_client_ops();
if (ops == NULL || ops->container.logs == NULL) {
ERROR("Unimplemented logs op");
ret = -1;
goto out;
}
request->id = util_strdup_s(args->name);
request->runtime = util_strdup_s(args->runtime);
request->follow = args->follow;
request->tail = (int64_t)args->tail;
config = get_connect_config(args);
ret = ops->container.logs(request, response, &config);
if (ret != 0) {
if (strncmp(response->errmsg, DISABLE_ERR_MESSAGE, strlen(DISABLE_ERR_MESSAGE)) == 0) {
fprintf(stdout, "[WARNING]: Container %s disable console log!\n", args->name);
ret = 0;
goto out;
}
client_print_error(response->cc, response->server_errono, response->errmsg);
ret = -1;
goto out;
}
out:
lcrc_logs_response_free(response);
lcrc_logs_request_free(request);
return ret;
}
int callback_tail(command_option_t *option, const char *arg)
{
if (util_safe_llong(arg, option->data)) {
*(long long *)option->data = -1;
}
return 0;
}
static int cmd_logs_init(int argc, const char **argv)
{
struct log_config lconf = { 0 };
command_t cmd;
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_logs_args)) {
COMMAND_ERROR("client arguments init failed\n");
return ECOMMON;
}
g_cmd_logs_args.progname = argv[0];
struct command_option options[] = {
LOG_OPTIONS(lconf),
LOGS_OPTIONS(g_cmd_logs_args),
COMMON_OPTIONS(g_cmd_logs_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_logs_desc,
g_cmd_logs_usage);
if (command_parse_args(&cmd, &g_cmd_logs_args.argc, &g_cmd_logs_args.argv)) {
return EINVALIDARGS;
}
if (log_init(&lconf)) {
COMMAND_ERROR("log init failed\n");
g_cmd_logs_args.name = g_cmd_logs_args.argv[0];
return ECOMMON;
}
if (g_cmd_logs_args.argc != 1) {
COMMAND_ERROR("Logs needs one container name");
return ECOMMON;
}
return 0;
}
int cmd_logs_main(int argc, const char **argv)
{
int ret = 0;
ret = cmd_logs_init(argc, argv);
if (ret != 0) {
exit(ret);
}
g_cmd_logs_args.name = g_cmd_logs_args.argv[0];
ret = do_logs(&g_cmd_logs_args);
if (ret != 0) {
exit(ECOMMON);
}
return 0;
}

View File

@ -0,0 +1,31 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container logs definition
******************************************************************************/
#ifndef __CMD_LOGS_H
#define __CMD_LOGS_H
#include "arguments.h"
#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 }
extern const char g_cmd_logs_desc[];
extern const char g_cmd_logs_usage[];
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);
#endif /* __CMD_LOGS_H */

View File

@ -0,0 +1,411 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container ps functions
******************************************************************************/
#include <string.h>
#include <errno.h>
#include "securec.h"
#include "arguments.h"
#include "ps.h"
#include "utils.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_list_desc[] = "List containers";
const char g_cmd_list_usage[] = "ps [command options]";
#define COMMAND_LENGTH_MAX 22
#define TIME_DURATION_MAX_LEN 32
struct client_arguments g_cmd_list_args = {
.dispname = false,
.list_all = false,
};
/* keep track of field widths for printing. */
struct lengths {
unsigned int id_length;
unsigned int state_length;
unsigned int image_length;
unsigned int command_length;
unsigned int init_length;
unsigned int exit_length;
unsigned int rscont_length;
unsigned int startat_length;
unsigned int finishat_length;
unsigned int runtime_length;
unsigned int name_length;
};
const char * const g_containerstatusstr[] = { "unknown", "inited", "starting", "running",
"exited", "paused", "restarting"
};
static const char *lcrc_lcrsta2str(Container_Status sta)
{
if (sta >= CONTAINER_STATUS_MAX_STATE) {
return NULL;
}
return g_containerstatusstr[sta];
}
static void list_print_quiet(struct lcrc_container_summary_info **info, const size_t size,
const struct lengths *length)
{
const char *status = NULL;
size_t i = 0;
for (i = 0; i < size; i++) {
const struct lcrc_container_summary_info *in = NULL;
in = info[i];
status = lcrc_lcrsta2str(in->status);
if (status == NULL) {
continue;
}
printf("%-*s ", (int)length->id_length, in->id ? in->id : "-");
printf("\n");
}
}
static int mix_container_status(const struct lcrc_container_summary_info *in, char *status, size_t len)
{
int ret = 0;
const char *container_status = NULL;
container_status = lcrc_lcrsta2str(in->status);
if (container_status == NULL) {
ret = strcpy_s(status, len, "-");
if (ret < 0) {
ERROR("Failed to copy string");
ret = -1;
goto out;
}
} else {
if (strcpy_s(status, len, container_status) != EOK) {
ERROR("Failed to copy string");
ret = -1;
goto out;
}
if (in->health_state != NULL) {
if (strcat_s(status, len, in->health_state) != EOK) {
ERROR("Failed to cat string");
ret = -1;
goto out;
}
}
}
out:
return ret;
}
static void ps_print_header(struct lengths *length)
{
/* print header */
printf("%-*s ", (int)length->state_length, "STATUS");
printf("%-*s ", (int)length->init_length, "PID");
printf("%-*s ", (int)length->image_length, "IMAGE");
if (length->command_length > COMMAND_LENGTH_MAX) {
printf("%-*s ", COMMAND_LENGTH_MAX, "COMMAND");
length->command_length = COMMAND_LENGTH_MAX;
} else {
printf("%-*s ", (int)length->command_length, "COMMAND");
}
printf("%-*s ", (int)length->exit_length, "EXIT_CODE");
printf("%-*s ", (int)length->rscont_length, "RESTART_COUNT");
printf("%-*s ", (int)length->startat_length, "STARTAT");
printf("%-*s ", (int)length->finishat_length, "FINISHAT");
printf("%-*s ", (int)length->runtime_length, "RUNTIME");
printf("%-*s ", (int)length->id_length, "ID");
printf("%-*s ", (int)length->name_length, "NAMES");
printf("\n");
}
static void ps_print_container_info_pre(const struct lcrc_container_summary_info *in, const char *status,
const struct lengths *length)
{
const char *cmd = (in->command != NULL) ? in->command : "-";
int cmd_len = (int)strlen(cmd);
printf("%-*s ", (int)length->state_length, status);
if (in->has_pid) {
printf("%-*u ", (int)length->init_length, in->pid);
} else {
printf("%-*s ", (int)length->init_length, "-");
}
printf("%-*s ", (int)length->image_length, in->image ? in->image : "none");
if (cmd_len > COMMAND_LENGTH_MAX - 2) {
printf("\"%-*.*s...\" ", COMMAND_LENGTH_MAX - 5, COMMAND_LENGTH_MAX - 5, cmd);
} else {
int space_len = ((int)(length->command_length) - cmd_len) - 2;
printf("\"%-*.*s\"%*s ", cmd_len, cmd_len, cmd, space_len, (space_len == 0) ? "" : " ");
}
}
static void ps_print_container_info(const struct lcrc_container_summary_info *in, const char *status,
const struct lengths *length)
{
char finishat_duration[TIME_DURATION_MAX_LEN] = { 0 };
char startat_duration[TIME_DURATION_MAX_LEN] = { 0 };
ps_print_container_info_pre(in, status, length);
printf("%-*u ", (int)length->exit_length, in->exit_code);
printf("%-*u ", (int)length->rscont_length, in->restart_count);
time_format_duration(in->startat, startat_duration, sizeof(startat_duration));
printf("%-*s ", (int)length->startat_length, in->startat ? startat_duration : "-");
time_format_duration(in->finishat, finishat_duration, sizeof(finishat_duration));
printf("%-*s ", (int)length->finishat_length, in->finishat ? finishat_duration : "-");
printf("%-*s ", (int)length->runtime_length, in->runtime ? in->runtime : "lcr");
printf("%-*.*s ", (int)length->id_length, (int)length->id_length, in->id ? in->id : "-");
printf("%-*s ", (int)length->name_length, in->name ? in->name : "-");
printf("\n");
}
static void list_print_table(struct lcrc_container_summary_info **info, const size_t size, struct lengths *length)
{
const struct lcrc_container_summary_info *in = NULL;
size_t i = 0;
char status[32] = { 0 };
ps_print_header(length);
for (i = 0; i < size; i++) {
in = info[i];
if (mix_container_status(in, status, sizeof(status))) {
return;
}
ps_print_container_info(in, status, length);
}
}
static void calculate_str_length(const char *str, unsigned int *length)
{
size_t len = 0;
if (str == NULL) {
return;
}
len = strlen(str);
if (len > (*length)) {
*length = (unsigned int)len;
}
}
static void calculate_status_str_length(const struct lcrc_container_summary_info *in, unsigned int *length)
{
const char *status = NULL;
status = lcrc_lcrsta2str(in->status);
if (status != NULL) {
size_t len;
len = strlen(status);
if (in->health_state != NULL) {
len += strlen(in->health_state);
}
if (len > (*length)) {
*length = (unsigned int)len;
}
}
}
static void calculate_uint_str_length(uint32_t data, unsigned int *length)
{
int len = 0;
char tmpbuffer[UINT_LEN + 1] = { 0 };
len = sprintf_s(tmpbuffer, sizeof(tmpbuffer), "%u", data);
if (len < 0) {
ERROR("sprintf buffer failed");
return;
}
if ((unsigned int)len > (*length)) {
*length = (unsigned int)len;
}
}
static void calculate_time_str_length(const char *str, unsigned int *length)
{
size_t len = 0;
char time_duration[TIME_DURATION_MAX_LEN];
if (time_format_duration(str, time_duration, sizeof(time_duration)) < 0) {
ERROR("Format time duration failed");
}
len = strlen(time_duration);
if (len > (*length)) {
*length = (unsigned int)len;
}
}
static void list_field_width(struct lcrc_container_summary_info **info, const size_t size, struct lengths *l)
{
size_t i = 0;
const struct lcrc_container_summary_info *in = NULL;
if (info == NULL || l == NULL) {
return;
}
for (i = 0; i < size; i++, in++) {
in = info[i];
calculate_str_length(in->name, &l->name_length);
calculate_str_length(in->runtime, &l->runtime_length);
calculate_status_str_length(in, &l->state_length);
if (in->pid != -1) {
calculate_uint_str_length(in->pid, &l->init_length);
}
calculate_str_length(in->image, &l->image_length);
if (in->command != NULL) {
size_t cmd_len;
cmd_len = strlen(in->command) + 2;
if (cmd_len > l->command_length) {
l->command_length = (unsigned int)cmd_len;
}
}
calculate_uint_str_length(in->exit_code, &l->exit_length);
calculate_uint_str_length(in->restart_count, &l->rscont_length);
if (in->startat != NULL) {
calculate_time_str_length(in->startat, &l->startat_length);
}
if (in->finishat != NULL) {
calculate_time_str_length(in->finishat, &l->finishat_length);
}
}
}
/*
* used by qsort function for comparing container start time
*/
static inline int lcrc_container_cmp(struct lcrc_container_summary_info **first,
struct lcrc_container_summary_info **second)
{
return strcmp((*second)->startat, (*first)->startat);
}
/*
* Create a list request message and call RPC
*/
static int client_list(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_list_request request = { 0 };
struct lcrc_list_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
struct lengths max_len = {
.name_length = 5, /* NAMES */
.id_length = 12, /* ID */
.state_length = 5, /* STATE */
.image_length = 5, /* IMAGE */
.command_length = 7, /* COMMAND */
.init_length = 3, /* PID */
.exit_length = 9, /* EXIT_CODE*/
.rscont_length = 13, /* RESTART_COUNT*/
.startat_length = 7, /* STARTAT*/
.finishat_length = 8, /* FINISHAT*/
.runtime_length = 7, /* RUNTIME */
};
response = util_common_calloc_s(sizeof(struct lcrc_list_response));
if (response == NULL) {
ERROR("Out of memory");
return -1;
}
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.list) {
ERROR("Unimplemented ops");
ret = -1;
goto out;
}
if (args->filters != NULL) {
request.filters = lcrc_filters_parse_args((const char **)args->filters, util_array_len(args->filters));
if (!request.filters) {
ERROR("Failed to parse filters args");
ret = -1;
goto out;
}
}
request.all = args->list_all;
config = get_connect_config(args);
ret = ops->container.list(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
goto out;
}
if (response->container_num != 0)
qsort(response->container_summary, (size_t)(response->container_num),
sizeof(struct lcrc_container_summary_info *), (int (*)(const void *, const void *))lcrc_container_cmp);
if (args->dispname) {
list_print_quiet(response->container_summary, response->container_num, &max_len);
} else {
list_field_width(response->container_summary, response->container_num, &max_len);
list_print_table(response->container_summary, response->container_num, &max_len);
}
out:
lcrc_filters_free(request.filters);
lcrc_list_response_free(response);
return ret;
}
int cmd_list_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
command_t cmd;
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_list_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_list_args.progname = argv[0];
struct command_option options[] = {
LOG_OPTIONS(lconf),
LIST_OPTIONS(g_cmd_list_args),
COMMON_OPTIONS(g_cmd_list_args)
};
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_list_desc,
g_cmd_list_usage);
if (command_parse_args(&cmd, &g_cmd_list_args.argc, &g_cmd_list_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("PS: log init failed");
exit(ECOMMON);
}
if (g_cmd_list_args.argc > 0) {
COMMAND_ERROR("%s: \"ps\" requires 0 arguments.", g_cmd_list_args.progname);
exit(ECOMMON);
}
if (client_list(&g_cmd_list_args)) {
ERROR("Can not ps any containers");
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,32 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container ps definition
******************************************************************************/
#ifndef __CMD_LIST_H
#define __CMD_LIST_H
#include "arguments.h"
#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 }
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);
#endif /* __CMD_LIST_H */

View File

@ -0,0 +1,156 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container remove functions
******************************************************************************/
#include "top.h"
#include <limits.h>
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
#include "commands.h"
#include "console.h"
#include "utils.h"
#include "securec.h"
#include "container_inspect.h"
#include "attach.h"
#include "commander.h"
const char g_cmd_top_desc[] = "Display the running processes of a container";
const char g_cmd_top_usage[] = "top [OPTIONS] CONTAINER [ps OPTIONS]";
struct client_arguments g_cmd_top_args = {};
static void client_top_info_server(const struct lcrc_top_response *response)
{
size_t i;
if (response->titles != NULL) {
printf("%s\n", response->titles);
}
if (response->processes_len == 0 || response->processes == NULL) {
return;
}
for (i = 0; i < response->processes_len; i++) {
printf("%s\n", response->processes[i]);
}
}
/*
* Create a rm request message and call RPC
*/
static int client_top(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_top_request request = { 0 };
struct lcrc_top_response *response = NULL;
container_inspect *inspect_data = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_top_response));
if (response == NULL) {
ERROR("TOP: Out of memory");
return -1;
}
if (inspect_container(args, &inspect_data)) {
ERROR("inspect data error");
ret = -1;
goto out;
}
if (inspect_data == NULL) {
ERROR("inspect data is null");
ret = -1;
goto out;
}
if (inspect_data->state != NULL && !inspect_data->state->running) {
COMMAND_ERROR("You cannot attach to a stopped container, start it first");
ret = -1;
goto out;
}
if (inspect_data->state != NULL && inspect_data->state->restarting) {
COMMAND_ERROR("You cannot attach to a restarting container, wait until it is running");
ret = -1;
goto out;
}
request.name = args->name;
request.ps_argc = args->argc;
request.ps_args = (char **)args->argv;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.top) {
ERROR("Unimplemented top op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.top(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
}
client_top_info_server(response);
out:
free_container_inspect(inspect_data);
lcrc_top_response_free(response);
return ret;
}
int cmd_top_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
command_t cmd;
struct command_option options[] = { LOG_OPTIONS(lconf), COMMON_OPTIONS(g_cmd_top_args) };
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_top_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_top_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_top_desc,
g_cmd_top_usage);
if (command_parse_args(&cmd, &g_cmd_top_args.argc, &g_cmd_top_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Top: log init failed");
exit(ECOMMON);
}
if (g_cmd_top_args.argc < 1) {
COMMAND_ERROR("\"%s top\" requires at least 1 argument(s).", g_cmd_top_args.progname);
COMMAND_ERROR("See '%s top --help'.", g_cmd_top_args.progname);
exit(EINVALIDARGS);
} else {
g_cmd_top_args.name = g_cmd_top_args.argv[0];
g_cmd_top_args.argc--;
g_cmd_top_args.argv++;
}
if (client_top(&g_cmd_top_args) != 0) {
ERROR("Container \"%s\" top failed", g_cmd_top_args.name);
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide container top definition
******************************************************************************/
#ifndef __CMD_TOP_H
#define __CMD_TOP_H
#include "arguments.h"
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);
#endif /* __CMD_TOP_H */

View File

@ -0,0 +1,124 @@
/******************************************************************************
* 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: tanyifeng
* Create: 2018-11-08
* Description: provide container version functions
******************************************************************************/
#include "version.h"
#include <stdio.h>
#include <stdlib.h>
#include "securec.h"
#include "utils.h"
#include "arguments.h"
#include "log.h"
#include "config.h"
#include "lcrc_connect.h"
const char g_cmd_version_desc[] = "Display information about lcrc";
const char g_cmd_version_usage[] = "version";
struct client_arguments g_cmd_version_args = {};
static void client_version_info_client()
{
printf("Client:\n");
printf(" Version:\t%s\n", VERSION);
printf(" Git commit:\t%s\n", LCRD_GIT_COMMIT);
printf(" Built:\t%s\n", LCRD_BUILD_TIME);
printf("\n");
}
static void client_version_info_oci_config()
{
printf("OCI config:\n");
printf(" Version:\t%s\n", OCI_VERSION);
printf(" Default file:\t%s\n", OCICONFIG_PATH);
printf("\n");
}
static void client_version_info_server(const struct lcrc_version_response *response)
{
printf("Server:\n");
printf(" Version:\t%s\n", response->version ? response->version : "");
printf(" Git commit:\t%s\n", response->git_commit ? response->git_commit : "");
printf(" Built:\t%s\n", response->build_time ? response->build_time : "");
printf("\n");
}
static int client_version(const struct client_arguments *args)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_version_request request = { 0 };
struct lcrc_version_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_version_response));
if (response == NULL) {
ERROR("Version: Out of memory");
return -1;
}
client_version_info_client();
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.version) {
ERROR("Unimplemented version op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.version(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
goto out;
}
client_version_info_server(response);
client_version_info_oci_config();
out:
lcrc_version_response_free(response);
return ret;
}
int cmd_version_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
command_t cmd;
struct command_option options[] = { LOG_OPTIONS(lconf), COMMON_OPTIONS(g_cmd_version_args) };
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_version_args)) {
COMMAND_ERROR("client arguments init failed\n");
exit(ECOMMON);
}
g_cmd_version_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_version_desc,
g_cmd_version_usage);
if (command_parse_args(&cmd, &g_cmd_version_args.argc, &g_cmd_version_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Version: log init failed");
exit(ECOMMON);
}
if (g_cmd_version_args.argc > 0) {
COMMAND_ERROR("%s: \"version\" requires 0 arguments.", g_cmd_version_args.progname);
exit(ECOMMON);
}
if (client_version(&g_cmd_version_args)) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* 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: tanyifeng
* Create: 2018-11-08
* Description: provide container version definition
******************************************************************************/
#ifndef __CMD_VERSION_H
#define __CMD_VERSION_H
#include "arguments.h"
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);
#endif /* __CMD_VERSION_H */

View File

@ -0,0 +1,133 @@
/******************************************************************************
* 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: tanyifeng
* Create: 2018-11-08
* Description: provide container wait functions
******************************************************************************/
#include "error.h"
#include "securec.h"
#include "wait.h"
#include "arguments.h"
#include "log.h"
#include "lcrc_connect.h"
const char g_cmd_wait_desc[] = "Block until one or more containers stop, then print their exit codes";
const char g_cmd_wait_usage[] = "wait [OPTIONS] CONTAINER [CONTAINER...]";
struct client_arguments g_cmd_wait_args = {};
/*
* Create a delete request message and call RPC
*/
int client_wait(const struct client_arguments *args, unsigned int *exit_code)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_wait_request request = { 0 };
struct lcrc_wait_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
response = util_common_calloc_s(sizeof(struct lcrc_wait_response));
if (response == NULL) {
ERROR("Wait: Out of memory");
return -1;
}
request.id = args->name;
if (args->custom_conf.auto_remove == false) {
request.condition = WAIT_CONDITION_STOPPED;
} else {
request.condition = WAIT_CONDITION_REMOVED;
}
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.wait) {
ERROR("Unimplemented wait op");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.wait(&request, response, &config);
if (ret) {
client_print_error(response->cc, response->server_errono, response->errmsg);
if (response->cc) {
ret = ESERVERERROR;
} else {
ret = ECOMMON;
}
goto out;
}
if (exit_code != NULL) {
*exit_code = (unsigned int)response->exit_code;
}
out:
lcrc_wait_response_free(response);
return ret;
}
int cmd_wait_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
unsigned int exit_code = 0;
int i = 0;
int status = 0;
command_t cmd;
struct command_option options[] = { LOG_OPTIONS(lconf), COMMON_OPTIONS(g_cmd_wait_args) };
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_wait_args)) {
COMMAND_ERROR("client arguments init failed");
exit(ECOMMON);
}
g_cmd_wait_args.progname = argv[0];
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_wait_desc,
g_cmd_wait_usage);
if (command_parse_args(&cmd, &g_cmd_wait_args.argc, &g_cmd_wait_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("Wait: log init failed");
exit(ECOMMON);
}
if (g_cmd_wait_args.socket == NULL) {
COMMAND_ERROR("Missing --host,-H option");
exit(EINVALIDARGS);
}
if (g_cmd_wait_args.argc == 0) {
COMMAND_ERROR("Wait requires at least 1 container names");
exit(EINVALIDARGS);
}
if (g_cmd_wait_args.argc >= MAX_CLIENT_ARGS) {
COMMAND_ERROR("You specify too many containers to wait.");
exit(EINVALIDARGS);
}
for (i = 0; i < g_cmd_wait_args.argc; i++) {
g_cmd_wait_args.name = g_cmd_wait_args.argv[i];
if (client_wait(&g_cmd_wait_args, &exit_code)) {
ERROR("Container \"%s\" wait failed", g_cmd_wait_args.name);
status = -1;
continue;
}
printf("%u\n", exit_code);
}
if (status) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

View File

@ -0,0 +1,26 @@
/******************************************************************************
* 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: tanyifeng
* Create: 2018-11-08
* Description: provide container wait definition
******************************************************************************/
#ifndef __CMD_WAIT_H
#define __CMD_WAIT_H
#include "arguments.h"
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);
#endif /* __CMD_WAIT_H */

188
src/cmd/lcrc/main.c Normal file
View File

@ -0,0 +1,188 @@
/******************************************************************************
* 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: lifeng
* Create: 2018-11-08
* Description: provide init process of lcrc
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "commands.h"
#include "create.h"
#include "ps.h"
#include "rm.h"
#include "start.h"
#include "inspect.h"
#include "stop.h"
#include "exec.h"
#include "run.h"
#include "images.h"
#include "rmi.h"
#include "wait.h"
#include "restart.h"
#include "logs.h"
#include "kill.h"
#include "load.h"
#include "update.h"
#include "attach.h"
#include "info.h"
#include "stats.h"
#include "export.h"
#include "cp.h"
#include "top.h"
#include "pull.h"
#include "login.h"
#include "logout.h"
#include "lcrc_connect.h"
#include "version.h"
#include "rename.h"
#include "utils.h"
// The list of our supported commands
struct command g_commands[] = {
{
// `create` sub-command
"create", cmd_create_main, g_cmd_create_desc, NULL, &g_cmd_create_args
},
{
// `rm` sub-command
"rm", cmd_delete_main, g_cmd_delete_desc, NULL, &g_cmd_delete_args
},
{
// `ps` sub-command
"ps", cmd_list_main, g_cmd_list_desc, NULL, &g_cmd_list_args
},
{
// `start` sub-command
"start", cmd_start_main, g_cmd_start_desc, NULL, &g_cmd_start_args
},
{
// `run` sub-command
"run", cmd_run_main, g_cmd_run_desc, NULL, &g_cmd_run_args
},
{
// `restart` sub-command
"restart", cmd_restart_main, g_cmd_restart_desc, NULL, &g_cmd_restart_args
},
{
// `inspect` sub-command
"inspect", cmd_inspect_main, g_cmd_inspect_desc, NULL, &g_cmd_inspect_args
},
#ifdef ENABLE_OCI_IMAGE
{
// `stats` sub-command
"stats",
cmd_stats_main,
g_cmd_stats_desc,
NULL,
&g_cmd_stats_args
},
{
// `cp` sub-command
"cp", cmd_cp_main, g_cmd_cp_desc, NULL, &g_cmd_cp_args
},
#endif
{
// `stop` sub-command
"stop", cmd_stop_main, g_cmd_stop_desc, NULL, &g_cmd_stop_args
},
{
// `version` sub-command
"version", cmd_version_main, g_cmd_version_desc, NULL, &g_cmd_version_args
},
{
// `exec` sub-command
"exec", cmd_exec_main, g_cmd_exec_desc, NULL, &g_cmd_exec_args
},
{
// `images` sub-command
"images", cmd_images_main, g_cmd_images_desc, NULL, &g_cmd_images_args
},
#ifdef ENABLE_OCI_IMAGE
{
// `info` sub-command
"info", cmd_info_main, g_cmd_info_desc, NULL, &g_cmd_info_args
},
#endif
{
// `remove images` sub-command
"rmi", cmd_rmi_main, g_cmd_rmi_desc, NULL, &g_cmd_rmi_args
},
#ifdef ENABLE_OCI_IMAGE
{
// `wait` sub-command
"wait", cmd_wait_main, g_cmd_wait_desc, NULL, &g_cmd_wait_args
},
{
// `wait` sub-command
"logs", cmd_logs_main, g_cmd_logs_desc, NULL, &g_cmd_logs_args
},
#endif
{
// `kill` sub-command
"kill", cmd_kill_main, g_cmd_kill_desc, NULL, &g_cmd_kill_args
},
{
// `load` sub-command
"load", cmd_load_main, g_cmd_load_desc, NULL, &g_cmd_load_args
},
#ifdef ENABLE_OCI_IMAGE
{
// `update` sub-command
"update", cmd_update_main, g_cmd_update_desc, NULL, &g_cmd_update_args
},
#endif
{
// `attach` sub-command
"attach", cmd_attach_main, g_cmd_attach_desc, NULL, &g_cmd_attach_args
},
#ifdef ENABLE_OCI_IMAGE
{
// `export` sub-command
"export", cmd_export_main, g_cmd_export_desc, NULL, &g_cmd_export_args
},
{
// `top` sub-command
"top", cmd_top_main, g_cmd_top_desc, NULL, &g_cmd_top_args
},
{
// `rename` sub-command
"rename",
cmd_rename_main,
g_cmd_rename_desc,
NULL,
&g_cmd_rename_args
},
{
// `pull` sub-command
"pull", cmd_pull_main, g_cmd_pull_desc, NULL, &g_cmd_pull_args
},
{
// `login` sub-command
"login", cmd_login_main, g_cmd_login_desc, NULL, &g_cmd_login_args
},
{
// `logout` sub-command
"logout", cmd_logout_main, g_cmd_logout_desc, NULL, &g_cmd_logout_args
},
#endif
{ NULL, NULL, NULL, NULL, NULL } // End of the list
};
int main(int argc, char **argv)
{
if (connect_client_ops_init()) {
return ECOMMON;
}
return run_command(g_commands, argc, (const char **)argv);
}

View File

@ -0,0 +1,7 @@
# get current directory sources files
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} lcrc_stream_srcs)
set(LCRC_STREAM_SRCS
${lcrc_stream_srcs}
PARENT_SCOPE
)

View File

@ -0,0 +1,389 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: lifeng
* Create: 2017-11-22
* Description: provide container attach functions
******************************************************************************/
#include <semaphore.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <pthread.h>
#include "securec.h"
#include "arguments.h"
#include "exec.h"
#include "log.h"
#include "lcrc_connect.h"
#include "console.h"
#include "utils.h"
#include "attach.h"
#include "commands.h"
const char g_cmd_attach_desc[] = "Attach to a running container";
const char g_cmd_attach_usage[] = "attach [OPTIONS] CONTAINER";
struct client_arguments g_cmd_attach_args = { 0 };
static int check_tty(bool tty, struct termios *oldtios, bool *reset_tty)
{
int istty = 0;
if (!tty) {
return 0;
}
istty = isatty(0);
if (istty) {
if (setup_tios(0, oldtios)) {
ERROR("Failed to setup terminal properties");
return -1;
}
*reset_tty = true;
} else {
INFO("the input device is not a TTY");
return 0;
}
return 0;
}
int inspect_container(const struct client_arguments *args, container_inspect **inspect_data)
{
int ret = 0;
struct lcrc_inspect_request inspect_request = { 0 };
struct lcrc_inspect_response *inspect_response = NULL;
client_connect_config_t config = { 0 };
lcrc_connect_ops *ops = NULL;
parser_error perr = NULL;
inspect_response = util_common_calloc_s(sizeof(struct lcrc_inspect_response));
if (inspect_response == NULL) {
COMMAND_ERROR("Out of memory");
return -1;
}
inspect_request.name = args->name;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.inspect) {
COMMAND_ERROR("Unimplemented ops");
ret = -1;
goto out;
}
config = get_connect_config(args);
ret = ops->container.inspect(&inspect_request, inspect_response, &config);
if (ret) {
client_print_error(inspect_response->cc, inspect_response->server_errono, inspect_response->errmsg);
goto out;
}
/* parse oci container json */
if (inspect_response == NULL || inspect_response->json == NULL) {
COMMAND_ERROR("Inspect data is empty");
ret = -1;
goto out;
}
*inspect_data = container_inspect_parse_data(inspect_response->json, NULL, &perr);
if (*inspect_data == NULL) {
COMMAND_ERROR("Can not parse inspect json: %s", perr);
ret = -1;
goto out;
}
out:
lcrc_inspect_response_free(inspect_response);
free(perr);
return ret;
}
static int inspect_container_and_check_state(const struct client_arguments *args,
container_inspect **container_inspect_data)
{
int ret = 0;
container_inspect *inspect_data = NULL;
if (args->name == NULL || container_inspect_data == NULL) {
ERROR("input name or inspect_data is null");
ret = -1;
goto out;
}
if (inspect_container(args, &inspect_data)) {
ERROR("inspect data error");
ret = -1;
goto out;
}
if (inspect_data == NULL) {
ERROR("inspect data is null");
ret = -1;
goto out;
}
if (inspect_data->state != NULL && !inspect_data->state->running) {
COMMAND_ERROR("You cannot attach to a stopped container, start it first");
ret = -1;
goto out;
}
if (inspect_data->state != NULL && inspect_data->state->paused) {
COMMAND_ERROR("You cannot attach to a paused container, unpause it first");
ret = -1;
goto out;
}
if (inspect_data->state != NULL && inspect_data->state->restarting) {
COMMAND_ERROR("You cannot attach to a restarting container, wait until it is running");
ret = -1;
goto out;
}
*container_inspect_data = inspect_data;
out:
return ret;
}
static int attach_cmd_init(int argc, const char **argv)
{
command_t cmd;
struct log_config lconf = { 0 };
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_attach_args)) {
COMMAND_ERROR("client arguments init failed\n");
exit(ECOMMON);
}
g_cmd_attach_args.progname = argv[0];
struct command_option options[] = { LOG_OPTIONS(lconf), COMMON_OPTIONS(g_cmd_attach_args) };
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_attach_desc,
g_cmd_attach_usage);
if (command_parse_args(&cmd, &g_cmd_attach_args.argc, &g_cmd_attach_args.argv)) {
return EINVALIDARGS;
}
if (log_init(&lconf)) {
COMMAND_ERROR("log init failed");
return ECOMMON;
}
if (g_cmd_attach_args.argc != 1) {
COMMAND_ERROR("\"%s attach\" requires exactly 1 argument(s).", g_cmd_attach_args.progname);
return ECOMMON;
}
g_cmd_attach_args.name = util_strdup_s(g_cmd_attach_args.argv[0]);
return 0;
}
struct wait_thread_arg {
struct client_arguments *client_args;
client_connect_config_t *config;
uint32_t *exit_code;
sem_t *sem_started;
sem_t *sem_exited;
};
static void *container_wait_thread_main(void *thread_arg)
{
int ret = -1;
lcrc_connect_ops *ops = NULL;
struct lcrc_wait_request request = { 0 };
struct lcrc_wait_response *response = NULL;
struct wait_thread_arg *arg = (struct wait_thread_arg *)thread_arg;
client_connect_config_t config = { 0 };
request.id = arg->client_args->name;
ret = pthread_detach(pthread_self());
if (ret != 0) {
CRIT("Set thread detach fail");
goto cleanup;
}
prctl(PR_SET_NAME, "AttachWaitThread");
response = util_common_calloc_s(sizeof(struct lcrc_wait_response));
if (response == NULL) {
ERROR("Wait: Out of memory");
goto cleanup;
}
request.condition = WAIT_CONDITION_STOPPED;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.wait) {
ERROR("Unimplemented wait op");
goto cleanup;
}
config = get_connect_config(arg->client_args);
(void)sem_post(arg->sem_started);
arg->sem_started = NULL;
ret = ops->container.wait(&request, response, &config);
if (ret != 0) {
ERROR("Wait failed");
goto cleanup;
}
*arg->exit_code = (uint32_t)response->exit_code;
cleanup:
if (arg->sem_started != NULL) {
(void)sem_post(arg->sem_started);
}
if (ret == 0) {
(void)sem_post(arg->sem_exited);
}
lcrc_wait_response_free(response);
free(arg);
return NULL;
}
static int container_wait_thread(struct client_arguments *args, uint32_t *exit_code, sem_t *sem_exited)
{
int ret = 0;
pthread_t tid;
struct wait_thread_arg *arg = NULL;
sem_t sem_started;
arg = util_common_calloc_s(sizeof(struct wait_thread_arg));
if (arg == NULL) {
ERROR("Out of memory");
return -1;
}
if (sem_init(&sem_started, 0, 0) != 0) {
COMMAND_ERROR("Can not init sem");
free(arg);
return -1;
}
arg->client_args = args;
arg->exit_code = exit_code;
arg->sem_started = &sem_started;
arg->sem_exited = sem_exited;
ret = pthread_create(&tid, NULL, container_wait_thread_main, arg);
if (ret != 0) {
free(arg);
(void)sem_destroy(&sem_started);
return -1;
}
(void)sem_wait(&sem_started);
(void)sem_destroy(&sem_started);
return 0;
}
static int client_attach(struct client_arguments *args, uint32_t *exit_code)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_attach_request request = { 0 };
struct lcrc_attach_response *response = NULL;
client_connect_config_t config = { 0 };
int ret = 0;
struct termios oldtios = { 0 };
bool reset_tty = false;
container_inspect *inspect_data = NULL;
sem_t sem_exited;
struct timespec ts;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.attach) {
COMMAND_ERROR("Unimplemented attach operation");
ret = ECOMMON;
goto out;
}
if (inspect_container_and_check_state(args, &inspect_data)) {
ERROR("Failed to get inspect info!");
ret = ECOMMON;
goto out;
}
if (sem_init(&sem_exited, 0, 0) != 0) {
COMMAND_ERROR("Can not init sem");
ret = ECOMMON;
goto out;
}
response = util_common_calloc_s(sizeof(struct lcrc_attach_response));
if (response == NULL) {
ERROR("Attach: Out of memory");
ret = ECOMMON;
goto out;
}
free(args->name);
args->name = util_strdup_s(inspect_data->id);
request.name = args->name;
request.attach_stdin = true;
request.attach_stdout = true;
request.attach_stderr = true;
if (check_tty(inspect_data->config->tty, &oldtios, &reset_tty) != 0) {
ret = ECOMMON;
goto out;
}
config = get_connect_config(args);
container_wait_thread(args, exit_code, &sem_exited);
ret = ops->container.attach(&request, response, &config);
if (ret != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
ret = ECOMMON;
goto out;
}
if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
ERROR("Failed to get real time");
ret = ECOMMON;
goto out;
}
ts.tv_sec++;
if (sem_timedwait(&sem_exited, &ts) != 0) {
if (errno == ETIMEDOUT) {
COMMAND_ERROR("Wait container status timeout.");
} else {
COMMAND_ERROR("Failed to wait sem: %s", strerror(errno));
}
ret = ECOMMON;
goto out;
}
out:
(void)sem_destroy(&sem_exited);
free_container_inspect(inspect_data);
lcrc_attach_response_free(response);
if (reset_tty) {
if (tcsetattr(0, TCSAFLUSH, &oldtios) < 0) {
ERROR("Failed to reset terminal properties");
return -1;
}
}
return ret;
}
int cmd_attach_main(int argc, const char **argv)
{
int ret = 0;
unsigned int exit_code = 0;
ret = attach_cmd_init(argc, argv);
if (ret != 0) {
goto out;
}
ret = client_attach(&g_cmd_attach_args, &exit_code);
if (ret != 0) {
ERROR("Failed to execute command attach");
goto out;
}
out:
exit((exit_code != 0) ? (int)exit_code : ret);
}

View File

@ -0,0 +1,27 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: lifeng
* Create: 2017-11-22
* Description: provide container attach definition
******************************************************************************/
#ifndef __CMD_ATTACH_H
#define __CMD_ATTACH_H
#include "arguments.h"
#include "container_inspect.h"
#include "wait.h"
extern const char g_cmd_attach_desc[];
extern const char g_cmd_attach_usage[];
extern struct client_arguments g_cmd_attach_args;
int inspect_container(const struct client_arguments *args, container_inspect **inspect_data);
int cmd_attach_main(int argc, const char **argv);
#endif /* __CMD_ATTACH_H */

350
src/cmd/lcrc/stream/cp.c Normal file
View File

@ -0,0 +1,350 @@
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2019-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: tanyifeng
* Create: 2019-04-17
* Description: provide container cp functions
******************************************************************************/
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "error.h"
#include "cp.h"
#include "arguments.h"
#include "log.h"
#include "path.h"
#include "lcrc_connect.h"
#include "securec.h"
#include "lcrdtar.h"
#define FromContainer 0x01u
#define ToContainer 0x10u
#define AcrossContainers 0x11u
const char g_cmd_cp_desc[] = "Copy files/folders between a container and the local filesystem";
const char g_cmd_cp_usage[] = "cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH\n"
" cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH";
struct client_arguments g_cmd_cp_args = {};
static char *resolve_local_path(const char *path)
{
char abs_path[PATH_MAX] = { 0 };
if (cleanpath(path, abs_path, sizeof(abs_path)) == NULL) {
ERROR("Failed to clean path");
return NULL;
}
return preserve_trailing_dot_or_separator(abs_path, path);
}
static void print_copy_from_container_error(const char *ops_err, const char *archive_err, int ret,
const struct client_arguments *args)
{
if (ops_err != NULL) {
if (strcmp(ops_err, errno_to_error_message(LCRD_ERR_CONNECT)) == 0) {
COMMAND_ERROR("%s", ops_err);
} else {
client_print_error(0, LCRD_ERR_EXEC, ops_err);
}
} else if (archive_err != NULL) {
COMMAND_ERROR("Failed exact archive: %s", archive_err);
} else if (ret != 0) {
COMMAND_ERROR("Failed to copy from container");
}
}
static int client_copy_from_container(const struct client_arguments *args, const char *id, const char *srcpath,
const char *destpath)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_copy_from_container_request request = { 0 };
struct lcrc_copy_from_container_response *response = NULL;
int ret = 0;
int nret = 0;
char *archive_err = NULL;
char *ops_err = NULL;
char *resolved = NULL;
struct archive_copy_info *srcinfo = NULL;
client_connect_config_t config;
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.copy_from_container) {
COMMAND_ERROR("Unimplemented copy from container operation");
return -1;
}
response = util_common_calloc_s(sizeof(struct lcrc_copy_from_container_response));
if (response == NULL) {
ERROR("Event: Out of memory");
return -1;
}
request.id = (char *)id;
request.runtime = args->runtime;
request.srcpath = (char *)srcpath;
config = get_connect_config(args);
ret = ops->container.copy_from_container(&request, response, &config);
if (ret) {
ops_err = (response->errmsg != NULL) ? util_strdup_s(response->errmsg) : NULL;
goto out;
}
resolved = resolve_local_path(destpath);
if (resolved == NULL) {
ret = -1;
goto out;
}
srcinfo = util_common_calloc_s(sizeof(struct archive_copy_info));
if (srcinfo == NULL) {
ret = -1;
goto out;
}
srcinfo->exists = true;
srcinfo->path = util_strdup_s(srcpath);
srcinfo->isdir = S_ISDIR(response->stat->mode);
nret = archive_copy_to(&response->reader, false, srcinfo, resolved, &archive_err);
if (nret != 0) {
ret = nret;
}
nret = response->reader.close(response->reader.context, &ops_err);
if (nret != 0) {
ret = nret;
}
out:
print_copy_from_container_error(ops_err, archive_err, ret, args);
free(resolved);
free(archive_err);
free(ops_err);
free_archive_copy_info(srcinfo);
lcrc_copy_from_container_response_free(response);
return ret;
}
static void print_copy_to_container_error(const struct lcrc_copy_to_container_response *response,
const char *archive_err, int ret, const struct client_arguments *args)
{
if (response->cc != LCRD_SUCCESS || response->errmsg != NULL || response->server_errono != 0) {
client_print_error(response->cc, response->server_errono, response->errmsg);
} else if (archive_err) {
COMMAND_ERROR("Failed to archive: %s", archive_err);
} else if (ret != 0) {
COMMAND_ERROR("Can not copy to container");
}
}
static int client_copy_to_container(const struct client_arguments *args, const char *id, const char *srcpath,
const char *destpath)
{
lcrc_connect_ops *ops = NULL;
struct lcrc_copy_to_container_request request = { 0 };
struct lcrc_copy_to_container_response *response = NULL;
int ret = 0;
int nret = 0;
char *archive_err = NULL;
char *resolved = NULL;
struct archive_copy_info *srcinfo = NULL;
struct io_read_wrapper archive_reader = { 0 };
client_connect_config_t config = { 0 };
ops = get_connect_client_ops();
if (ops == NULL || !ops->container.copy_to_container) {
COMMAND_ERROR("Unimplemented copy to container operation");
return -1;
}
response = util_common_calloc_s(sizeof(struct lcrc_copy_to_container_response));
if (response == NULL) {
ERROR("Event: Out of memory");
return -1;
}
request.id = (char *)id;
request.runtime = args->runtime;
request.dstpath = (char *)destpath;
resolved = resolve_local_path(srcpath);
if (resolved == NULL) {
ret = -1;
goto out;
}
srcinfo = copy_info_source_path(resolved, false, &archive_err);
if (srcinfo == NULL) {
ret = -1;
goto out;
}
nret = tar_resource(srcinfo, &archive_reader, &archive_err);
if (nret != 0) {
ret = -1;
goto out;
}
request.srcpath = srcinfo->path;
request.srcisdir = srcinfo->isdir;
request.srcrebase = srcinfo->rebase_name;
request.reader.context = archive_reader.context;
request.reader.read = archive_reader.read;
request.reader.close = archive_reader.close;
config = get_connect_config(args);
ret = ops->container.copy_to_container(&request, response, &config);
if (ret) {
goto out;
}
nret = archive_reader.close(archive_reader.context, &archive_err);
if (nret < 0) {
ret = nret;
}
out:
print_copy_to_container_error(response, archive_err, ret, args);
free(resolved);
free(archive_err);
free_archive_copy_info(srcinfo);
lcrc_copy_to_container_response_free(response);
return ret;
}
static void ignore_sigpipe()
{
struct sigaction sa;
/*
* Ignore SIGPIPE so the current process still exists after child process exited.
*/
if (memset_s(&sa, sizeof(struct sigaction), 0, sizeof(struct sigaction)) != EOK) {
WARN("Failed to set memory");
}
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGPIPE, &sa, NULL) < 0) {
WARN("Failed to ignore SIGPIPE");
}
}
static int client_run_copy(const struct client_arguments *args, const char *source, const char *destination)
{
int ret = 0;
char *dup_src = NULL;
char *dup_dest = NULL;
char *colon = NULL;
char *src_container = NULL;
char *src_path = NULL;
char *dest_container = NULL;
char *dest_path = NULL;
char *container = NULL;
unsigned int direction = 0;
ignore_sigpipe();
dup_src = util_strdup_s(source);
src_path = dup_src;
colon = strchr(dup_src, ':');
if (colon != NULL) {
*colon++ = '\0';
src_container = dup_src;
src_path = colon;
}
dup_dest = util_strdup_s(destination);
dest_path = dup_dest;
colon = strchr(dup_dest, ':');
if (colon != NULL) {
*colon++ = '\0';
dest_container = dup_dest;
dest_path = colon;
}
if (src_container != NULL && src_container[0] != '\0') {
direction |= FromContainer;
container = src_container;
}
if (dest_container != NULL && dest_container[0] != '\0') {
direction |= ToContainer;
container = dest_container;
}
if (direction == FromContainer) {
ret = client_copy_from_container(args, container, src_path, dest_path);
goto cleanup;
}
if (direction == ToContainer) {
ret = client_copy_to_container(args, container, src_path, dest_path);
goto cleanup;
}
if (direction == AcrossContainers) {
COMMAND_ERROR("copying between containers is not supported");
goto cleanup;
}
COMMAND_ERROR("must specify at least one container source");
cleanup:
free(dup_src);
free(dup_dest);
return ret;
}
int cmd_cp_main(int argc, const char **argv)
{
struct log_config lconf = { 0 };
command_t cmd;
set_default_command_log_config(argv[0], &lconf);
if (client_arguments_init(&g_cmd_cp_args)) {
COMMAND_ERROR("client arguments init failed\n");
exit(ECOMMON);
}
g_cmd_cp_args.progname = argv[0];
struct command_option options[] = { LOG_OPTIONS(lconf), COMMON_OPTIONS(g_cmd_cp_args) };
command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_cp_desc,
g_cmd_cp_usage);
if (command_parse_args(&cmd, &g_cmd_cp_args.argc, &g_cmd_cp_args.argv)) {
exit(EINVALIDARGS);
}
if (log_init(&lconf)) {
COMMAND_ERROR("cp: log init failed");
exit(ECOMMON);
}
if (g_cmd_cp_args.argc != 2) {
COMMAND_ERROR("\"%s cp\" requires exactly 2 arguments.", g_cmd_cp_args.progname);
exit(ECOMMON);
}
if (g_cmd_cp_args.socket == NULL) {
COMMAND_ERROR("Missing --host,-H option");
exit(EINVALIDARGS);
}
if (client_run_copy(&g_cmd_cp_args, g_cmd_cp_args.argv[0], g_cmd_cp_args.argv[1]) != 0) {
exit(ECOMMON);
}
exit(EXIT_SUCCESS);
}

Some files were not shown because too many files have changed in this diff Show More