in pkg/kube/inject/inject.go [606:798]
func IntoObject(injector Injector, sidecarTemplate Templates, valuesConfig ValuesConfig,
revision string, meshconfig *meshconfig.MeshConfig, in runtime.Object, warningHandler func(string)) (interface{}, error) {
out := in.DeepCopyObject()
var deploymentMetadata metav1.ObjectMeta
var metadata *metav1.ObjectMeta
var podSpec *corev1.PodSpec
var typeMeta metav1.TypeMeta
// Handle Lists
if list, ok := out.(*corev1.List); ok {
result := list
for i, item := range list.Items {
obj, err := FromRawToObject(item.Raw)
if runtime.IsNotRegisteredError(err) {
continue
}
if err != nil {
return nil, err
}
r, err := IntoObject(injector, sidecarTemplate, valuesConfig, revision, meshconfig, obj, warningHandler) // nolint: vetshadow
if err != nil {
return nil, err
}
re := runtime.RawExtension{}
re.Object = r.(runtime.Object)
result.Items[i] = re
}
return result, nil
}
// CronJobs have JobTemplates in them, instead of Templates, so we
// special case them.
switch v := out.(type) {
case *batch.CronJob:
job := v
typeMeta = job.TypeMeta
metadata = &job.Spec.JobTemplate.ObjectMeta
deploymentMetadata = job.ObjectMeta
podSpec = &job.Spec.JobTemplate.Spec.Template.Spec
case *corev1.Pod:
pod := v
typeMeta = pod.TypeMeta
metadata = &pod.ObjectMeta
deploymentMetadata = pod.ObjectMeta
podSpec = &pod.Spec
case *appsv1.Deployment: // Added to be explicit about the most expected case
deploy := v
typeMeta = deploy.TypeMeta
deploymentMetadata = deploy.ObjectMeta
metadata = &deploy.Spec.Template.ObjectMeta
podSpec = &deploy.Spec.Template.Spec
default:
// `in` is a pointer to an Object. Dereference it.
outValue := reflect.ValueOf(out).Elem()
typeMeta = outValue.FieldByName("TypeMeta").Interface().(metav1.TypeMeta)
deploymentMetadata = outValue.FieldByName("ObjectMeta").Interface().(metav1.ObjectMeta)
templateValue := outValue.FieldByName("Spec").FieldByName("Template")
// `Template` is defined as a pointer in some older API
// definitions, e.g. ReplicationController
if templateValue.Kind() == reflect.Ptr {
if templateValue.IsNil() {
return out, fmt.Errorf("spec.template is required value")
}
templateValue = templateValue.Elem()
}
metadata = templateValue.FieldByName("ObjectMeta").Addr().Interface().(*metav1.ObjectMeta)
podSpec = templateValue.FieldByName("Spec").Addr().Interface().(*corev1.PodSpec)
}
name := metadata.Name
if name == "" {
name = deploymentMetadata.Name
}
namespace := metadata.Namespace
if namespace == "" {
namespace = deploymentMetadata.Namespace
}
var fullName string
if deploymentMetadata.Namespace != "" {
fullName = fmt.Sprintf("%s/%s", deploymentMetadata.Namespace, name)
} else {
fullName = name
}
kind := typeMeta.Kind
// Skip injection when host networking is enabled. The problem is
// that the iptable changes are assumed to be within the pod when,
// in fact, they are changing the routing at the host level. This
// often results in routing failures within a node which can
// affect the network provider within the cluster causing
// additional pod failures.
if podSpec.HostNetwork {
warningStr := fmt.Sprintf("===> Skipping injection because %q has host networking enabled\n",
fullName)
if kind != "" {
warningStr = fmt.Sprintf("===> Skipping injection because %s %q has host networking enabled\n",
kind, fullName)
}
warningHandler(warningStr)
return out, nil
}
// skip injection for injected pods
if len(podSpec.Containers) > 1 {
_, hasStatus := metadata.Annotations[annotation.SidecarStatus.Name]
for _, c := range podSpec.Containers {
if c.Name == ProxyContainerName && hasStatus {
warningStr := fmt.Sprintf("===> Skipping injection because %q has injected %q sidecar already\n",
fullName, ProxyContainerName)
if kind != "" {
warningStr = fmt.Sprintf("===> Skipping injection because %s %s %q has host networking enabled\n",
kind, fullName, ProxyContainerName)
}
warningHandler(warningStr)
return out, nil
}
}
}
pod := &corev1.Pod{
ObjectMeta: *metadata,
Spec: *podSpec,
}
var patchBytes []byte
var err error
if injector != nil {
patchBytes, err = injector.Inject(pod, namespace)
}
if err != nil {
return nil, err
}
// TODO(Monkeyanator) istioctl injection still applies just the pod annotation since we don't have
// the ProxyConfig CRs here.
if pca, f := metadata.GetAnnotations()[annotation.ProxyConfig.Name]; f {
var merr error
meshconfig, merr = mesh.ApplyProxyConfig(pca, meshconfig)
if merr != nil {
return nil, merr
}
}
if patchBytes == nil {
if !injectRequired(IgnoredNamespaces.UnsortedList(), &Config{Policy: InjectionPolicyEnabled}, &pod.Spec, pod.ObjectMeta) {
warningStr := fmt.Sprintf("===> Skipping injection because %q has sidecar injection disabled\n", fullName)
if kind != "" {
warningStr = fmt.Sprintf("===> Skipping injection because %s %q has sidecar injection disabled\n",
kind, fullName)
}
warningHandler(warningStr)
return out, nil
}
params := InjectionParameters{
pod: pod,
deployMeta: deploymentMetadata,
typeMeta: typeMeta,
// Todo replace with some template resolver abstraction
templates: sidecarTemplate,
defaultTemplate: []string{SidecarTemplateName},
meshConfig: meshconfig,
proxyConfig: meshconfig.GetDefaultConfig(),
valuesConfig: valuesConfig,
revision: revision,
proxyEnvs: map[string]string{},
injectedAnnotations: nil,
}
patchBytes, err = injectPod(params)
}
if err != nil {
return nil, err
}
patched, err := applyJSONPatchToPod(pod, patchBytes)
if err != nil {
return nil, err
}
patchedObject, _, err := jsonSerializer.Decode(patched, nil, &corev1.Pod{})
if err != nil {
return nil, err
}
patchedPod := patchedObject.(*corev1.Pod)
*metadata = patchedPod.ObjectMeta
*podSpec = patchedPod.Spec
return out, nil
}