mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Merge pull request #91452 from claudiubelu/windows/pause-image
Add support for building Windows pause image
This commit is contained in:
commit
68e4f1ff64
@ -20,6 +20,7 @@ filegroup(
|
|||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [
|
srcs = [
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
|
"//build/pause/windows/wincat:all-srcs",
|
||||||
"//build/release-tars:all-srcs",
|
"//build/release-tars:all-srcs",
|
||||||
"//build/visible_to:all-srcs",
|
"//build/visible_to:all-srcs",
|
||||||
],
|
],
|
||||||
|
@ -152,7 +152,7 @@ dependencies:
|
|||||||
match: tag =
|
match: tag =
|
||||||
|
|
||||||
- name: "k8s.gcr.io/pause"
|
- name: "k8s.gcr.io/pause"
|
||||||
version: 3.3
|
version: 3.4
|
||||||
refPaths:
|
refPaths:
|
||||||
- path: build/pause/Makefile
|
- path: build/pause/Makefile
|
||||||
match: TAG =
|
match: TAG =
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM scratch
|
ARG BASE
|
||||||
|
FROM ${BASE}
|
||||||
ARG ARCH
|
ARG ARCH
|
||||||
ADD bin/pause-${ARCH} /pause
|
ADD bin/pause-linux-${ARCH} /pause
|
||||||
ENTRYPOINT ["/pause"]
|
ENTRYPOINT ["/pause"]
|
||||||
|
25
build/pause/Dockerfile_windows
Normal file
25
build/pause/Dockerfile_windows
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Copyright 2020 The Kubernetes Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
ARG BASE
|
||||||
|
FROM ${BASE}
|
||||||
|
ARG ARCH
|
||||||
|
ADD bin/pause-windows-${ARCH}.exe /pause.exe
|
||||||
|
ADD bin/wincat-windows-amd64 /Windows/System32/wincat.exe
|
||||||
|
|
||||||
|
# NOTE(claudiub): docker buildx sets the PATH env variable to a Linux-like PATH,
|
||||||
|
# which is not desirable. See: https://github.com/moby/buildkit/issues/1560
|
||||||
|
# TODO(claudiub): remove this once the issue has been resolved.
|
||||||
|
ENV PATH="C:\Windows\system32;C:\Windows;"
|
||||||
|
ENTRYPOINT ["/pause.exe"]
|
@ -12,91 +12,132 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
.PHONY: all push container clean orphan all-push push-manifest
|
.PHONY: all container clean orphan all-push push-manifest
|
||||||
|
|
||||||
REGISTRY ?= staging-k8s.gcr.io
|
REGISTRY ?= staging-k8s.gcr.io
|
||||||
IMAGE = $(REGISTRY)/pause
|
IMAGE = $(REGISTRY)/pause
|
||||||
IMAGE_WITH_ARCH = $(IMAGE)-$(ARCH)
|
IMAGE_WITH_OS_ARCH = $(IMAGE)-$(OS)-$(ARCH)
|
||||||
|
|
||||||
TAG = 3.3
|
TAG = 3.4
|
||||||
REV = $(shell git describe --contains --always --match='v*')
|
REV = $(shell git describe --contains --always --match='v*')
|
||||||
|
|
||||||
# Architectures supported: amd64, arm, arm64, ppc64le and s390x
|
# Architectures supported: amd64, arm, arm64, ppc64le and s390x
|
||||||
ARCH ?= amd64
|
ARCH ?= amd64
|
||||||
|
# Operating systems supported: linux, windows
|
||||||
|
OS ?= linux
|
||||||
|
# OS Version for the Windows images: 1809, 1903, 1909 2004
|
||||||
|
OSVERSION ?= 1809 1903 1909 2004
|
||||||
|
|
||||||
ALL_ARCH = amd64 arm arm64 ppc64le s390x
|
# The output type could either be docker (local), or registry.
|
||||||
|
# If it is registry, it will also allow us to push the Windows images.
|
||||||
|
OUTPUT_TYPE ?= docker
|
||||||
|
|
||||||
|
ALL_OS = linux windows
|
||||||
|
ALL_ARCH.linux = amd64 arm arm64 ppc64le s390x
|
||||||
|
ALL_OS_ARCH.linux = $(foreach arch, ${ALL_ARCH.linux}, linux-$(arch))
|
||||||
|
ALL_ARCH.windows = amd64
|
||||||
|
ALL_OSVERSIONS.windows := 1809 1903 1909 2004
|
||||||
|
ALL_OS_ARCH.windows = $(foreach arch, $(ALL_ARCH.windows), $(foreach osversion, ${ALL_OSVERSIONS.windows}, windows-$(arch)-${osversion}))
|
||||||
|
ALL_OS_ARCH = $(foreach os, $(ALL_OS), ${ALL_OS_ARCH.${os}})
|
||||||
|
|
||||||
CFLAGS = -Os -Wall -Werror -static -DVERSION=v$(TAG)-$(REV)
|
CFLAGS = -Os -Wall -Werror -static -DVERSION=v$(TAG)-$(REV)
|
||||||
KUBE_CROSS_IMAGE ?= k8s.gcr.io/build-image/kube-cross
|
KUBE_CROSS_IMAGE.linux ?= k8s.gcr.io/build-image/kube-cross
|
||||||
KUBE_CROSS_VERSION ?= $(shell cat ../build-image/cross/VERSION)
|
KUBE_CROSS_VERSION.linux ?= $(shell cat ../build-image/cross/VERSION)
|
||||||
|
KUBE_CROSS_IMAGE.windows ?= dockcross/windows-static-x64
|
||||||
|
KUBE_CROSS_VERSION.windows ?= latest
|
||||||
|
KUBE_CROSS_IMAGE := ${KUBE_CROSS_IMAGE.${OS}}
|
||||||
|
KUBE_CROSS_VERSION := ${KUBE_CROSS_VERSION.${OS}}
|
||||||
|
|
||||||
BIN = pause
|
# NOTE(claudiub): The Windows pause image also requires the wincat binary we're compiling for the
|
||||||
SRCS = pause.c
|
# port-forwarding scenarios. If it's no longer necessary, it can be removed.
|
||||||
|
# For more information, see: https://github.com/kubernetes/kubernetes/pull/91452
|
||||||
|
BIN.linux = pause
|
||||||
|
BIN.windows = pause wincat
|
||||||
|
BIN := ${BIN.${OS}}
|
||||||
|
SRCS.linux = linux/pause.c
|
||||||
|
SRCS.windows = windows/pause.c
|
||||||
|
SRCS := ${SRCS.${OS}}
|
||||||
|
|
||||||
ifeq ($(ARCH),amd64)
|
EXTENSION.linux =
|
||||||
TRIPLE ?= x86_64-linux-gnu
|
EXTENSION.windows = .exe
|
||||||
endif
|
EXTENSION := ${EXTENSION.${OS}}
|
||||||
|
|
||||||
ifeq ($(ARCH),arm)
|
# The manifest command is still experimental as of Docker 18.09.3
|
||||||
TRIPLE ?= arm-linux-gnueabihf
|
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(ARCH),arm64)
|
TRIPLE.windows-amd64 := x86_64-w64-mingw32.static
|
||||||
TRIPLE ?= aarch64-linux-gnu
|
TRIPLE.linux-amd64 := x86_64-linux-gnu
|
||||||
endif
|
TRIPLE.linux-arm := arm-linux-gnueabihf
|
||||||
|
TRIPLE.linux-arm64 := aarch64-linux-gnu
|
||||||
ifeq ($(ARCH),ppc64le)
|
TRIPLE.linux-ppc64le := powerpc64le-linux-gnu
|
||||||
TRIPLE ?= powerpc64le-linux-gnu
|
TRIPLE.linux-s390x := s390x-linux-gnu
|
||||||
endif
|
TRIPLE := ${TRIPLE.${OS}-${ARCH}}
|
||||||
|
BASE.linux := scratch
|
||||||
ifeq ($(ARCH),s390x)
|
BASE.windows := mcr.microsoft.com/windows/nanoserver
|
||||||
TRIPLE ?= s390x-linux-gnu
|
BASE := ${BASE.${OS}}
|
||||||
endif
|
|
||||||
|
|
||||||
# If you want to build AND push all containers, see the 'all-push' rule.
|
# If you want to build AND push all containers, see the 'all-push' rule.
|
||||||
all: all-container
|
all: all-container-docker
|
||||||
|
|
||||||
all-push: all-push-images push-manifest
|
# NOTE(claudiub): A non-default builder instance is needed in order to build Windows images.
|
||||||
|
all-push: all-container-registry push-manifest
|
||||||
|
|
||||||
push-manifest:
|
push-manifest:
|
||||||
docker manifest create --amend $(IMAGE):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(IMAGE)\-&:$(TAG)~g")
|
docker manifest create --amend $(IMAGE):$(TAG) $(shell echo $(ALL_OS_ARCH) | sed -e "s~[^ ]*~$(IMAGE)\-&:$(TAG)~g")
|
||||||
set -x; for arch in $(ALL_ARCH); do docker manifest annotate --arch $${arch} ${IMAGE}:${TAG} ${IMAGE}-$${arch}:${TAG}; done
|
set -x; for arch in $(ALL_ARCH.linux); do docker manifest annotate --os linux --arch $${arch} ${IMAGE}:${TAG} ${IMAGE}-linux-$${arch}:${TAG}; done
|
||||||
|
# For Windows images, we also need to include the "os.version" in the manifest list, so the Windows node can pull the proper image it needs.
|
||||||
|
# At the moment, docker manifest annotate doesn't allow us to set the os.version, so we'll have to it ourselves. The manifest list can be found locally as JSONs.
|
||||||
|
# See: https://github.com/moby/moby/issues/41417
|
||||||
|
# TODO(claudiub): Clean this up once the above issue has been fixed.
|
||||||
|
set -x; \
|
||||||
|
registry_prefix=$(shell (echo ${REGISTRY} | grep -Eq "[a-z]*") && echo "docker.io/" || echo ""); \
|
||||||
|
manifest_image_folder=`echo "$${registry_prefix}${IMAGE}" | sed "s|/|_|g" | sed "s/:/-/"`; \
|
||||||
|
for arch in $(ALL_ARCH.windows); do \
|
||||||
|
for osversion in ${ALL_OSVERSIONS.windows}; do \
|
||||||
|
docker manifest annotate --os windows --arch $${arch} ${IMAGE}:${TAG} ${IMAGE}-windows-$${arch}-$${osversion}:${TAG}; \
|
||||||
|
BASEIMAGE=${BASE.windows}:$${osversion}; \
|
||||||
|
full_version=`docker manifest inspect ${BASE.windows}:$${osversion} | grep "os.version" | head -n 1 | awk '{print $$2}'` || true; \
|
||||||
|
sed -i -r "s/(\"os\"\:\"windows\")/\0,\"os.version\":$${full_version}/" "${HOME}/.docker/manifests/$${manifest_image_folder}-${TAG}/$${manifest_image_folder}-windows-$${arch}-$${osversion}-${TAG}"; \
|
||||||
|
done; \
|
||||||
|
done
|
||||||
docker manifest push --purge ${IMAGE}:${TAG}
|
docker manifest push --purge ${IMAGE}:${TAG}
|
||||||
|
|
||||||
|
all-container-docker: $(addprefix sub-container-docker-,$(ALL_OS_ARCH.linux))
|
||||||
|
all-container-registry: $(addprefix sub-container-registry-,$(ALL_OS_ARCH))
|
||||||
|
|
||||||
|
# split words on hyphen, access by 1-index
|
||||||
|
word-hyphen = $(word $2,$(subst -, ,$1))
|
||||||
sub-container-%:
|
sub-container-%:
|
||||||
$(MAKE) ARCH=$* container
|
$(MAKE) OUTPUT_TYPE=$(call word-hyphen,$*,1) OS=$(call word-hyphen,$*,2) ARCH=$(call word-hyphen,$*,3) OSVERSION=$(call word-hyphen,$*,4) container
|
||||||
|
|
||||||
sub-push-%:
|
build: $(foreach binary, ${BIN}, bin/${binary}-${OS}-${ARCH})
|
||||||
$(MAKE) ARCH=$* push
|
|
||||||
|
|
||||||
all-container: $(addprefix sub-container-,$(ALL_ARCH))
|
bin/${BIN.linux}-$(OS)-$(ARCH): $(SRCS)
|
||||||
|
|
||||||
all-push-images: $(addprefix sub-push-,$(ALL_ARCH))
|
|
||||||
|
|
||||||
build: bin/$(BIN)-$(ARCH)
|
|
||||||
|
|
||||||
bin/$(BIN)-$(ARCH): $(SRCS)
|
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/build \
|
docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/build \
|
||||||
$(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \
|
$(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \
|
||||||
/bin/bash -c "\
|
/bin/bash -c "\
|
||||||
cd /build && \
|
cd /build && \
|
||||||
$(TRIPLE)-gcc $(CFLAGS) -o $@ $^ && \
|
$(TRIPLE)-gcc $(CFLAGS) -o $@ $^ && \
|
||||||
$(TRIPLE)-strip $@"
|
$(TRIPLE)-strip $(foreach binary, $@, ${binary}${EXTENSION})"
|
||||||
|
|
||||||
container: .container-$(ARCH)
|
bin/wincat-windows-${ARCH}: windows/wincat/wincat.go
|
||||||
.container-$(ARCH): bin/$(BIN)-$(ARCH)
|
CGO_ENABLED=0 GOOS=windows GOARCH=${ARCH} go build -o $@ $^
|
||||||
DOCKER_CLI_EXPERIMENTAL=enabled docker buildx build --load --pull --platform linux/$(ARCH) -t $(IMAGE_WITH_ARCH):$(TAG) --build-arg ARCH=$(ARCH) .
|
|
||||||
|
container: .container-${OS}-$(ARCH)
|
||||||
|
.container-linux-$(ARCH): bin/$(BIN)-$(OS)-$(ARCH)
|
||||||
|
docker buildx build --pull --output=type=${OUTPUT_TYPE} --platform ${OS}/$(ARCH) \
|
||||||
|
-t $(IMAGE_WITH_OS_ARCH):$(TAG) --build-arg BASE=${BASE} --build-arg ARCH=$(ARCH) .
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
push: .push-$(ARCH)
|
.container-windows-$(ARCH): $(foreach binary, ${BIN}, bin/${binary}-${OS}-${ARCH})
|
||||||
.push-$(ARCH): .container-$(ARCH)
|
docker buildx build --pull --output=type=${OUTPUT_TYPE} --platform ${OS}/$(ARCH) \
|
||||||
docker push $(IMAGE_WITH_ARCH):$(TAG)
|
-t $(IMAGE_WITH_OS_ARCH)-${OSVERSION}:$(TAG) --build-arg BASE=${BASE}:${OSVERSION} --build-arg ARCH=$(ARCH) -f Dockerfile_windows .
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
# Useful for testing, not automatically included in container image
|
# Useful for testing, not automatically included in container image
|
||||||
orphan: bin/orphan-$(ARCH)
|
orphan: bin/orphan-linux-$(ARCH)
|
||||||
bin/orphan-$(ARCH): orphan.c
|
bin/orphan-linux-$(ARCH): linux/orphan.c
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
docker run -u $$(id -u):$$(id -g) -v $$(pwd):/build \
|
docker run -u $$(id -u):$$(id -g) -v $$(pwd):/build \
|
||||||
$(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \
|
$(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \
|
||||||
@ -106,4 +147,4 @@ bin/orphan-$(ARCH): orphan.c
|
|||||||
$(TRIPLE)-strip $@"
|
$(TRIPLE)-strip $@"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf .container-* .push-* bin/
|
rm -rf .*-container-* .push-* bin/
|
||||||
|
@ -16,4 +16,5 @@ steps:
|
|||||||
- '-c'
|
- '-c'
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
|
&& docker buildx create --name img-builder --use \
|
||||||
&& make all-push
|
&& make all-push
|
||||||
|
49
build/pause/windows/pause.c
Normal file
49
build/pause/windows/pause.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
|
||||||
|
{
|
||||||
|
switch (fdwCtrlType)
|
||||||
|
{
|
||||||
|
case CTRL_C_EVENT:
|
||||||
|
fprintf(stderr, "Shutting down, got signal\n");
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
case CTRL_BREAK_EVENT:
|
||||||
|
fprintf(stderr, "Shutting down, got signal\n");
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
if (SetConsoleCtrlHandler(CtrlHandler, TRUE))
|
||||||
|
{
|
||||||
|
Sleep(INFINITE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("\nERROR: Could not set control handler\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
28
build/pause/windows/wincat/BUILD
Normal file
28
build/pause/windows/wincat/BUILD
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["wincat.go"],
|
||||||
|
importpath = "k8s.io/kubernetes/build/pause/windows/wincat",
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_binary(
|
||||||
|
name = "windows",
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
78
build/pause/windows/wincat/wincat.go
Normal file
78
build/pause/windows/wincat/wincat.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package main connects to the given host and port and redirects its stdin to the connection and
|
||||||
|
// the connection's output to stdout. This is currently being used for port-forwarding for Windows Pods.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 3 {
|
||||||
|
log.Fatalln("usage: wincat <host> <port>")
|
||||||
|
}
|
||||||
|
host := os.Args[1]
|
||||||
|
port := os.Args[2]
|
||||||
|
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%s", host, port))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to resolve TCP addr %v %v", host, port)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialTCP("tcp", nil, addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to connect to %s:%s because %s", host, port, err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
os.Stdout.Close()
|
||||||
|
os.Stdin.Close()
|
||||||
|
conn.CloseRead()
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := io.Copy(os.Stdout, conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error while copying stream to stdout: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
conn.CloseWrite()
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := io.Copy(conn, os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error while copying stream from stdin: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user