From b6644de6e1eb863d3e82d0e294797a81582e95af Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Tue, 23 Sep 2025 15:37:44 +0800 Subject: [PATCH] fix --- apps/efka/src/docker/docker_uds_commands.erl | 327 ++++++++++++------- 1 file changed, 204 insertions(+), 123 deletions(-) diff --git a/apps/efka/src/docker/docker_uds_commands.erl b/apps/efka/src/docker/docker_uds_commands.erl index c29d2cb..4631801 100644 --- a/apps/efka/src/docker/docker_uds_commands.erl +++ b/apps/efka/src/docker/docker_uds_commands.erl @@ -36,6 +36,8 @@ check_image_exist(Image) when is_binary(Image) -> -spec create_container(ContainerName :: binary(), ContainerDir :: string(), Config :: map()) -> {ok, ContainerId :: binary()} | {error, Reason :: any()}. create_container(ContainerName, ContainerDir, Config) when is_binary(ContainerName), is_list(ContainerDir), is_map(Config) -> + Url = "/containers/create", + Image = maps:get(<<"image">>, Config), Cmd = maps:get(<<"command">>, Config, []), @@ -145,188 +147,267 @@ gather_output(Port, Acc) -> {Status, iolist_to_binary(Acc)} end. --spec gather_pull_output(Port :: port(), Callback :: fun((Msg :: binary()) -> no_return())) -> ExitCode :: integer(). -gather_pull_output(Port, Callback) -> - receive - {Port, {data, Data}} -> - Callback(Data), - gather_pull_output(Port, Callback); - {Port, {exit_status, Status}} -> - Status - end. +%% 构建最终 JSON Map +build_options(Config) when is_map(Config) -> + maps:merge( + #{ + <<"Image">> => maps:get(<<"image">>, Config, <<>>), + <<"Cmd">> => maps:get(<<"command">>, Config, []), + <<"Entrypoint">> => maps:get(<<"entrypoint">>, Config, []), + <<"Env">> => maps:get(<<"envs">>, Config, []) + }, + fold_merge([ + build_expose(Config), + build_volumes(Config), + build_networks(Config), + build_labels(Config), + build_restart(Config), + build_user(Config), + build_working_dir(Config), + build_hostname(Config), + build_privileged(Config), + build_cap_add_drop(Config), + build_devices(Config), + build_memory(Config), + build_cpu(Config), + build_ulimits(Config), + build_sysctls(Config), + build_tmpfs(Config), + build_extra_hosts(Config), + build_healthcheck(Config) + ]) + ). -%% 构建所有参数 -build_options(Config) -> - lists:flatten([ - build_entrypoint(Config), - build_ports(Config), - build_expose(Config), - build_volumes(Config), - build_env(Config), - build_env_file(Config), - build_networks(Config), - build_labels(Config), - build_restart(Config), - build_user(Config), - build_working_dir(Config), - build_hostname(Config), - build_privileged(Config), - build_cap_add_drop(Config), - build_devices(Config), - build_memory(Config), - build_cpu(Config), - build_ulimits(Config), - build_sysctls(Config), - build_tmpfs(Config), - build_extra_hosts(Config), - build_healthcheck(Config) - ]). - -build_entrypoint(Config) -> - case maps:get(<<"entrypoint">>, Config, []) of - [] -> []; - EP -> [<<"--entrypoint">> | EP] - end. - -build_ports(Config) -> - Ports = maps:get(<<"ports">>, Config, []), - lists:map(fun(P) -> [<<"-p">>, P] end, Ports). +%% 工具函数 +fold_merge(List) -> + lists:foldl(fun maps:merge/2, #{}, List). +%% --- 构建子字段 --- build_expose(Config) -> Ports = maps:get(<<"expose">>, Config, []), - lists:map(fun(P) -> [<<"--expose">>, P] end, Ports). + case Ports of + [] -> #{}; + _ -> + Exposed = maps:from_list([{<

>, #{}} || P <- Ports]), + #{<<"ExposedPorts">> => Exposed} + end. build_volumes(Config) -> Vols = maps:get(<<"volumes">>, Config, []), - lists:map(fun(V) -> [<<"-v">>, V] end, Vols). - -build_env(Config) -> - Envs = maps:get(<<"envs">>, Config, []), - lists:map(fun(E) -> [<<"-e">>, E] end, Envs). - -build_env_file(Config) -> - Files = maps:get(<<"env_file">>, Config, []), - lists:map(fun(F) -> [<<"--env-file">>, F] end, Files). + case Vols of + [] -> #{}; + _ -> + HostBinds = Vols, + VolMap = maps:from_list(lists:map(fun(V) -> + [_Host, Cont] = binary:split(V, <<":">>, []), + {Cont, #{}} + end, Vols)), + #{ + <<"HostConfig">> => #{ + <<"Binds">> => HostBinds + }, + <<"Volumes">> => VolMap + } + end. build_networks(Config) -> Nets = maps:get(<<"networks">>, Config, []), - lists:map(fun(Net) -> [<<"--network">>, Net] end, Nets). + case Nets of + [] -> #{}; + _ -> + NetCfg = maps:from_list([{N, #{}} || N <- Nets]), + #{<<"NetworkingConfig">> => #{<<"EndpointsConfig">> => NetCfg}} + end. build_labels(Config) -> - case maps:get(<<"labels">>, Config, #{}) of - #{} -> - []; - Labels -> - lists:map(fun({K, V}) -> [<<"--label">>, <>, Config, #{}), + case maps:size(Labels) of + 0 -> #{}; + _ -> #{<<"Labels">> => Labels} end. build_restart(Config) -> case maps:get(<<"restart">>, Config, undefined) of - undefined -> []; - Policy -> [<<"--restart">>, Policy] + undefined -> + #{}; + Policy -> + #{<<"HostConfig">> => #{<<"RestartPolicy">> => #{<<"Name">> => Policy}}} end. build_user(Config) -> case maps:get(<<"user">>, Config, undefined) of - undefined -> []; - U -> [<<"--user">>, U] + undefined -> + #{}; + U -> + #{<<"User">> => U} end. build_working_dir(Config) -> case maps:get(<<"working_dir">>, Config, undefined) of - undefined -> []; - D -> [<<"--workdir">>, D] + undefined -> + #{}; + D -> + #{<<"WorkingDir">> => D} end. build_hostname(Config) -> case maps:get(<<"hostname">>, Config, undefined) of - undefined -> []; - H -> [<<"--hostname">>, H] + undefined -> + #{}; + H -> + #{<<"Hostname">> => H} end. build_privileged(Config) -> case maps:get(<<"privileged">>, Config, false) of - true -> [<<"--privileged">>]; - _ -> [] + true -> + #{<<"HostConfig">> => #{<<"Privileged">> => true}}; + _ -> + #{} end. build_cap_add_drop(Config) -> Add = maps:get(<<"cap_add">>, Config, []), Drop = maps:get(<<"cap_drop">>, Config, []), - lists:map(fun(C) -> [<<"--cap-add">>, C] end, Add) ++ lists:map(fun(C0) -> [<<"--cap-drop">>, C0] end, Drop). + case {Add, Drop} of + {[], []} -> + #{}; + _ -> + #{<<"HostConfig">> => #{<<"CapAdd">> => Add, <<"CapDrop">> => Drop}} + end. build_devices(Config) -> Devs = maps:get(<<"devices">>, Config, []), - lists:map(fun(D) -> [<<"--device">>, D] end, Devs). + case Devs of + [] -> + #{}; + _ -> + DevObjs = [#{<<"PathOnHost">> => H, <<"PathInContainer">> => C, + <<"CgroupPermissions">> => <<"rwm">>} + || D <- Devs, + [H, C] <- [binary:split(D, <<":">>, [])]], + #{<<"HostConfig">> => #{<<"Devices">> => DevObjs}} + end. build_memory(Config) -> Mem = maps:get(<<"mem_limit">>, Config, undefined), MemRes = maps:get(<<"mem_reservation">>, Config, undefined), - Res1 = if Mem /= undefined -> [<<"--memory">>, Mem]; true -> [] end, - Res2 = if MemRes /= undefined -> [<<"--memory-reservation">>, MemRes]; true -> [] end, - Res1 ++ Res2. + HCfg = #{}, + HCfg1 = if + Mem /= undefined -> + maps:put(<<"Memory">>, parse_mem(Mem), HCfg); + true -> + HCfg + end, + HCfg2 = if + MemRes /= undefined -> + maps:put(<<"MemoryReservation">>, parse_mem(MemRes), HCfg1); + true -> + HCfg1 + end, + case maps:size(HCfg2) of + 0 -> #{}; + _ -> #{<<"HostConfig">> => HCfg2} + end. + +parse_mem(Val) -> + case binary:last(Val) of + $m -> + N = binary:part(Val, {0, byte_size(Val)-1}), + list_to_integer(binary_to_list(N)) * 1024 * 1024; + $g -> + N = binary:part(Val, {0, byte_size(Val)-1}), + list_to_integer(binary_to_list(N)) * 1024 * 1024 * 1024; + _ -> + list_to_integer(binary_to_list(Val)) + end. build_cpu(Config) -> CPU = maps:get(<<"cpus">>, Config, undefined), Shares = maps:get(<<"cpu_shares">>, Config, undefined), - Res1 = if - CPU /= undefined -> - Bin = iolist_to_binary(io_lib:format("~p", [CPU])), - [<<"--cpus">>, Bin]; - true -> - [] - end, - Res2 = if - Shares /= undefined -> - Bin1 = iolist_to_binary(io_lib:format("~p", [Shares])), - [<<"--cpu-shares">>, Bin1]; - true -> - [] - end, - Res1 ++ Res2. + HCfg = #{}, + HCfg1 = if + CPU /= undefined -> + maps:put(<<"NanoCpus">>, trunc(CPU * 1000000000), HCfg); + true -> + HCfg + end, + HCfg2 = if + Shares /= undefined -> + maps:put(<<"CpuShares">>, Shares, HCfg1); + true -> + HCfg1 + end, + case maps:size(HCfg2) of + 0 -> #{}; + _ -> #{<<"HostConfig">> => HCfg2} + end. build_ulimits(Config) -> - UL = maps:get(<<"ulimits">>, Config, #{}), - lists:map(fun({K, V}) -> [<<"--ulimit">>, <>, Config, #{}), + case maps:size(UL) of + 0 -> #{}; + _ -> + ULList = [#{<<"Name">> => K, <<"Soft">> => S, <<"Hard">> => H} + || {K, V} <- maps:to_list(UL), + [S1, H1] <- [binary:split(V, <<":">>, [])], + S = list_to_integer(binary_to_list(S1)), + H = list_to_integer(binary_to_list(H1))], + + #{<<"HostConfig">> => #{<<"Ulimits">> => ULList}} + end. build_sysctls(Config) -> SC = maps:get(<<"sysctls">>, Config, #{}), - lists:map(fun({K, V}) -> [<<"--sysctl ">>, <> => #{<<"Sysctls">> => SC}} + end. build_tmpfs(Config) -> Tmp = maps:get(<<"tmpfs">>, Config, []), - lists:map(fun(T) -> [<<"--tmpfs">>, T] end, Tmp). + case Tmp of + [] -> + #{}; + _ -> + #{<<"HostConfig">> => #{<<"Tmpfs">> => maps:from_list([{T, <<>>} || T <- Tmp])}} + end. build_extra_hosts(Config) -> Hosts = maps:get(<<"extra_hosts">>, Config, []), - lists:map(fun(H) -> [<<"--add-host">>, H] end, Hosts). + case Hosts of + [] -> + #{}; + _ -> + #{<<"HostConfig">> => #{<<"ExtraHosts">> => Hosts}} + end. build_healthcheck(Config) -> HC = maps:get(<<"healthcheck">>, Config, #{}), - lists:map(fun({K, V}) -> - case K of - <<"test">> -> - case V of - %% Test 是 ["CMD-SHELL", Cmd] - [<<"CMD-SHELL">>, Cmd] -> - [<<"--health-cmd">>, <<$", Cmd/binary, $">>]; - %% Test 是 ["CMD", Arg1, Arg2...] - [<<"CMD">> | CmdList] -> - CmdArgs = iolist_to_binary(lists:join(<<" ">>, CmdList)), - [<<"--health-cmd">>, <<$", CmdArgs/binary, $">>]; - %% Test 是 <<"NONE">> - [<<"NONE">>] -> - [<<"--no-healthcheck">>]; - _ -> - [] - end; - <<"interval">> -> - [<<"--health-interval">>, V]; - <<"timeout">> -> - [<<"--health-timeout">>, V]; - <<"retries">> -> - [<<"--health-retries">>, io_lib:format("~p", [V])]; - _ -> - [] - end - end, maps:to_list(HC)). + case maps:size(HC) of + 0 -> #{}; + _ -> + HCMap = #{ + <<"Test">> => maps:get(<<"test">>, HC, []), + <<"Interval">> => parse_duration(maps:get(<<"interval">>, HC, <<"0s">>)), + <<"Timeout">> => parse_duration(maps:get(<<"timeout">>, HC, <<"0s">>)), + <<"Retries">> => maps:get(<<"retries">>, HC, 0) + }, + #{<<"Healthcheck">> => HCMap} + end. + +parse_duration(Bin) -> + %% "30s" -> 30000000000 + Sz = byte_size(Bin), + NBin = binary:part(Bin, {0, Sz-1}), + N = list_to_integer(binary_to_list(NBin)), + case binary:last(Bin) of + $s -> + N * 1000000000; + $m -> + N * 60000000000; + _ -> + N + end. \ No newline at end of file