Merge pull request #99576 from marosset/windows-host-process-work
Windows host process work
This commit is contained in:
@@ -5357,6 +5357,16 @@ type WindowsSecurityContextOptions struct {
|
||||
// PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||
// +optional
|
||||
RunAsUserName *string
|
||||
|
||||
// HostProcess determines if a container should be run as a 'Host Process' container.
|
||||
// This field is alpha-level and will only be honored by components that enable the
|
||||
// WindowsHostProcessContainers feature flag. Setting this field without the feature
|
||||
// flag will result in errors when validating the Pod. All of a Pod's containers must
|
||||
// have the same effective HostProcess value (it is not allowed to have a mix of HostProcess
|
||||
// containers and non-HostProcess containers). In addition, if HostProcess is true
|
||||
// then HostNetwork must also be set to true.
|
||||
// +optional
|
||||
HostProcess *bool
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
2
pkg/apis/core/v1/zz_generated.conversion.go
generated
2
pkg/apis/core/v1/zz_generated.conversion.go
generated
@@ -8212,6 +8212,7 @@ func autoConvert_v1_WindowsSecurityContextOptions_To_core_WindowsSecurityContext
|
||||
out.GMSACredentialSpecName = (*string)(unsafe.Pointer(in.GMSACredentialSpecName))
|
||||
out.GMSACredentialSpec = (*string)(unsafe.Pointer(in.GMSACredentialSpec))
|
||||
out.RunAsUserName = (*string)(unsafe.Pointer(in.RunAsUserName))
|
||||
out.HostProcess = (*bool)(unsafe.Pointer(in.HostProcess))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8224,6 +8225,7 @@ func autoConvert_core_WindowsSecurityContextOptions_To_v1_WindowsSecurityContext
|
||||
out.GMSACredentialSpecName = (*string)(unsafe.Pointer(in.GMSACredentialSpecName))
|
||||
out.GMSACredentialSpec = (*string)(unsafe.Pointer(in.GMSACredentialSpec))
|
||||
out.RunAsUserName = (*string)(unsafe.Pointer(in.RunAsUserName))
|
||||
out.HostProcess = (*bool)(unsafe.Pointer(in.HostProcess))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -3204,6 +3204,8 @@ type PodValidationOptions struct {
|
||||
AllowInvalidPodDeletionCost bool
|
||||
// Allow pod spec to use non-integer multiple of huge page unit size
|
||||
AllowIndivisibleHugePagesValues bool
|
||||
// Allow hostProcess field to be set in windows security context
|
||||
AllowWindowsHostProcessField bool
|
||||
}
|
||||
|
||||
// ValidatePodSingleHugePageResources checks if there are multiple huge
|
||||
@@ -3327,6 +3329,7 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi
|
||||
allErrs = append(allErrs, validatePodDNSConfig(spec.DNSConfig, &spec.DNSPolicy, fldPath.Child("dnsConfig"))...)
|
||||
allErrs = append(allErrs, validateReadinessGates(spec.ReadinessGates, fldPath.Child("readinessGates"))...)
|
||||
allErrs = append(allErrs, validateTopologySpreadConstraints(spec.TopologySpreadConstraints, fldPath.Child("topologySpreadConstraints"))...)
|
||||
allErrs = append(allErrs, validateWindowsHostProcessPod(spec, fldPath, opts)...)
|
||||
if len(spec.ServiceAccountName) > 0 {
|
||||
for _, msg := range ValidateServiceAccountName(spec.ServiceAccountName, false) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceAccountName"), spec.ServiceAccountName, msg))
|
||||
@@ -5974,6 +5977,91 @@ func validateWindowsSecurityContextOptions(windowsOptions *core.WindowsSecurityC
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateWindowsHostProcessPod(podSpec *core.PodSpec, fieldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
// Keep track of container and hostProcess container count for validate
|
||||
containerCount := 0
|
||||
hostProcessContainerCount := 0
|
||||
|
||||
var podHostProcess *bool
|
||||
if podSpec.SecurityContext != nil && podSpec.SecurityContext.WindowsOptions != nil {
|
||||
podHostProcess = podSpec.SecurityContext.WindowsOptions.HostProcess
|
||||
}
|
||||
|
||||
if !opts.AllowWindowsHostProcessField && podHostProcess != nil {
|
||||
// Do not allow pods to persist data that sets hostProcess (true or false)
|
||||
errMsg := "not allowed when feature gate 'WindowsHostProcessContainers' is not enabled"
|
||||
allErrs = append(allErrs, field.Forbidden(fieldPath.Child("securityContext", "windowsOptions", "hostProcess"), errMsg))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
hostNetwork := false
|
||||
if podSpec.SecurityContext != nil {
|
||||
hostNetwork = podSpec.SecurityContext.HostNetwork
|
||||
}
|
||||
|
||||
podshelper.VisitContainersWithPath(podSpec, fieldPath, func(c *core.Container, cFieldPath *field.Path) bool {
|
||||
containerCount++
|
||||
|
||||
var containerHostProcess *bool = nil
|
||||
if c.SecurityContext != nil && c.SecurityContext.WindowsOptions != nil {
|
||||
containerHostProcess = c.SecurityContext.WindowsOptions.HostProcess
|
||||
}
|
||||
|
||||
if !opts.AllowWindowsHostProcessField && containerHostProcess != nil {
|
||||
// Do not allow pods to persist data that sets hostProcess (true or false)
|
||||
errMsg := "not allowed when feature gate 'WindowsHostProcessContainers' is not enabled"
|
||||
allErrs = append(allErrs, field.Forbidden(cFieldPath.Child("securityContext", "windowsOptions", "hostProcess"), errMsg))
|
||||
}
|
||||
|
||||
if podHostProcess != nil && containerHostProcess != nil && *podHostProcess != *containerHostProcess {
|
||||
errMsg := fmt.Sprintf("pod hostProcess value must be identical if both are specified, was %v", *podHostProcess)
|
||||
allErrs = append(allErrs, field.Invalid(cFieldPath.Child("securityContext", "windowsOptions", "hostProcess"), *containerHostProcess, errMsg))
|
||||
}
|
||||
|
||||
switch {
|
||||
case containerHostProcess != nil && *containerHostProcess:
|
||||
// Container explitly sets hostProcess=true
|
||||
hostProcessContainerCount++
|
||||
case containerHostProcess == nil && podHostProcess != nil && *podHostProcess:
|
||||
// Container inherits hostProcess=true from pod settings
|
||||
hostProcessContainerCount++
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if hostProcessContainerCount > 0 {
|
||||
// Fail Pod validation if feature is not enabled (unless podspec already exists and contains HostProcess fields) instead of dropping fields based on PRR reivew.
|
||||
if !opts.AllowWindowsHostProcessField {
|
||||
errMsg := "pod must not contain Windows hostProcess containers when feature gate 'WindowsHostProcessContainers' is not enabled"
|
||||
allErrs = append(allErrs, field.Forbidden(fieldPath, errMsg))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// At present, if a Windows Pods contains any HostProcess containers than all containers must be
|
||||
// HostProcess containers (explicitly set or inherited).
|
||||
if hostProcessContainerCount != containerCount {
|
||||
errMsg := "If pod contains any hostProcess containers then all containers must be HostProcess containers"
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, "", errMsg))
|
||||
}
|
||||
|
||||
// At present Windows Pods which contain HostProcess containers must also set HostNetwork.
|
||||
if hostNetwork != true {
|
||||
errMsg := "hostNetwork must be true if pod contains any hostProcess containers"
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath.Child("hostNetwork"), hostNetwork, errMsg))
|
||||
}
|
||||
|
||||
if !capabilities.Get().AllowPrivileged {
|
||||
errMsg := "hostProcess containers are disallowed by cluster policy"
|
||||
allErrs = append(allErrs, field.Forbidden(fieldPath, errMsg))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidatePodLogOptions(opts *core.PodLogOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if opts.TailLines != nil && *opts.TailLines < 0 {
|
||||
|
@@ -17399,3 +17399,393 @@ func TestValidateNonSpecialIP(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateWindowsHostProcessPod(t *testing.T) {
|
||||
const containerName = "container"
|
||||
falseVar := false
|
||||
trueVar := true
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectError bool
|
||||
featureEnabled bool
|
||||
allowPrivileged bool
|
||||
podSpec *core.PodSpec
|
||||
}{
|
||||
{
|
||||
name: "Spec with feature disabled and pod-wide HostProcess=false and should not validate",
|
||||
expectError: true,
|
||||
featureEnabled: false,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &falseVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature disabled and pod-wide HostProcess=nil set should valildate",
|
||||
expectError: false,
|
||||
featureEnabled: false,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: nil,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature disabled and container setting HostProcess=true should not valildate",
|
||||
expectError: true,
|
||||
featureEnabled: false,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature disabled and init container setting HostProcess=true should not valildate",
|
||||
expectError: true,
|
||||
featureEnabled: false,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
InitContainers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, pod-wide HostProcess=true, and HostNetwork unset should not validate",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, pod-wide HostProcess=ture, and HostNetwork set should validate",
|
||||
expectError: false,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, pod-wide HostProcess=ture, HostNetwork set, and containers setting HostProcess=true should validate",
|
||||
expectError: false,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
InitContainers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, pod-wide HostProcess=nil, HostNetwork set, and all containers setting HostProcess=true should validate",
|
||||
expectError: false,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
InitContainers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Pods with feature enabled, some containers setting HostProcess=true, and others setting HostProcess=false should not validate",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
InitContainers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &falseVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, some containers setting HostProcess=true, and other leaving HostProcess unset should not validate",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
InitContainers: []core.Container{{
|
||||
Name: containerName,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, pod-wide HostProcess=true, some containers setting HostProcess=true, and init containers setting HostProcess=false should not validate",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
InitContainers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &falseVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, pod-wide HostProcess=true, some containers setting HostProcess=true, and others setting HostProcess=false should not validate",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &falseVar,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, pod-wide HostProcess=true, some containers setting HostProcess=true, and others leaving HostProcess=nil should validate",
|
||||
expectError: false,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
InitContainers: []core.Container{{
|
||||
Name: containerName,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Spec with feature enabled, pod-wide HostProcess=false, some contaienrs setting HostProccess=true should not validate",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &falseVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
InitContainers: []core.Container{{
|
||||
Name: containerName,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Pod's HostProcess set to true but all containers override to false should not validate",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: true,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &falseVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Valid HostProcess pod should spec should not validate if allowPrivileged is not set",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
allowPrivileged: false,
|
||||
podSpec: &core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
HostNetwork: true,
|
||||
},
|
||||
Containers: []core.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &core.SecurityContext{
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{
|
||||
HostProcess: &trueVar,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.WindowsHostProcessContainers, testCase.featureEnabled)()
|
||||
|
||||
opts := PodValidationOptions{AllowWindowsHostProcessField: testCase.featureEnabled}
|
||||
|
||||
capabilities.SetForTests(capabilities.Capabilities{
|
||||
AllowPrivileged: testCase.allowPrivileged,
|
||||
})
|
||||
|
||||
errs := validateWindowsHostProcessPod(testCase.podSpec, field.NewPath("spec"), opts)
|
||||
if testCase.expectError && len(errs) == 0 {
|
||||
t.Errorf("Unexpected success")
|
||||
}
|
||||
if !testCase.expectError && len(errs) != 0 {
|
||||
t.Errorf("Unexpected error(s): %v", errs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
5
pkg/apis/core/zz_generated.deepcopy.go
generated
5
pkg/apis/core/zz_generated.deepcopy.go
generated
@@ -5895,6 +5895,11 @@ func (in *WindowsSecurityContextOptions) DeepCopyInto(out *WindowsSecurityContex
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.HostProcess != nil {
|
||||
in, out := &in.HostProcess, &out.HostProcess
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user