github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/domain/infra/abi/generate.go (about)

     1  package abi
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/hanks177/podman/v4/libpod"
    10  	"github.com/hanks177/podman/v4/libpod/define"
    11  	"github.com/hanks177/podman/v4/pkg/domain/entities"
    12  	k8sAPI "github.com/hanks177/podman/v4/pkg/k8s.io/api/core/v1"
    13  	"github.com/hanks177/podman/v4/pkg/systemd/generate"
    14  	"github.com/ghodss/yaml"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
    19  	// First assume it's a container.
    20  	ctr, ctrErr := ic.Libpod.LookupContainer(nameOrID)
    21  	if ctrErr == nil {
    22  		// Generate the unit for the container.
    23  		name, content, err := generate.ContainerUnit(ctr, options)
    24  		if err != nil {
    25  			return nil, err
    26  		}
    27  		return &entities.GenerateSystemdReport{Units: map[string]string{name: content}}, nil
    28  	}
    29  
    30  	// If it's not a container, we either have a pod or garbage.
    31  	pod, err := ic.Libpod.LookupPod(nameOrID)
    32  	if err != nil {
    33  		err = errors.Wrap(ctrErr, err.Error())
    34  		return nil, errors.Wrapf(err, "%s does not refer to a container or pod", nameOrID)
    35  	}
    36  
    37  	// Generate the units for the pod and all its containers.
    38  	units, err := generate.PodUnits(pod, options)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return &entities.GenerateSystemdReport{Units: units}, nil
    43  }
    44  
    45  func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
    46  	var (
    47  		pods       []*libpod.Pod
    48  		ctrs       []*libpod.Container
    49  		vols       []*libpod.Volume
    50  		podContent [][]byte
    51  		content    [][]byte
    52  	)
    53  
    54  	// Lookup for podman objects.
    55  	for _, nameOrID := range nameOrIDs {
    56  		// Let's assume it's a container, so get the container.
    57  		ctr, err := ic.Libpod.LookupContainer(nameOrID)
    58  		if err != nil {
    59  			if !strings.Contains(err.Error(), "no such container") {
    60  				return nil, err
    61  			}
    62  		} else {
    63  			//  now that infra holds NS data, we need to support dependencies.
    64  			// we cannot deal with ctrs already in a pod.
    65  			if len(ctr.PodID()) > 0 {
    66  				return nil, errors.Errorf("container %s is associated with pod %s: use generate on the pod itself", ctr.ID(), ctr.PodID())
    67  			}
    68  			ctrs = append(ctrs, ctr)
    69  			continue
    70  		}
    71  
    72  		// Maybe it's a pod.
    73  		pod, err := ic.Libpod.LookupPod(nameOrID)
    74  		if err != nil {
    75  			if !strings.Contains(err.Error(), "no such pod") {
    76  				return nil, err
    77  			}
    78  		} else {
    79  			pods = append(pods, pod)
    80  			continue
    81  		}
    82  
    83  		// Or volume.
    84  		vol, err := ic.Libpod.LookupVolume(nameOrID)
    85  		if err != nil {
    86  			if !strings.Contains(err.Error(), "no such volume") {
    87  				return nil, err
    88  			}
    89  		} else {
    90  			vols = append(vols, vol)
    91  			continue
    92  		}
    93  
    94  		// If it reaches here is because the name or id did not exist.
    95  		return nil, errors.Errorf("Name or ID %q not found", nameOrID)
    96  	}
    97  
    98  	// Generate kube persistent volume claims from volumes.
    99  	if len(vols) >= 1 {
   100  		pvs, err := getKubePVCs(vols)
   101  		if err != nil {
   102  			return nil, err
   103  		}
   104  
   105  		content = append(content, pvs...)
   106  	}
   107  
   108  	// Generate kube pods and services from pods.
   109  	if len(pods) >= 1 {
   110  		pos, svcs, err := getKubePods(ctx, pods, options.Service)
   111  		if err != nil {
   112  			return nil, err
   113  		}
   114  
   115  		podContent = append(podContent, pos...)
   116  		if options.Service {
   117  			content = append(content, svcs...)
   118  		}
   119  	}
   120  
   121  	// Generate the kube pods from containers.
   122  	if len(ctrs) >= 1 {
   123  		po, err := libpod.GenerateForKube(ctx, ctrs)
   124  		if err != nil {
   125  			return nil, err
   126  		}
   127  		if len(po.Spec.Volumes) != 0 {
   128  			warning := `
   129  # NOTE: If you generated this yaml from an unprivileged and rootless podman container on an SELinux
   130  # enabled system, check the podman generate kube man page for steps to follow to ensure that your pod/container
   131  # has the right permissions to access the volumes added.
   132  `
   133  			content = append(content, []byte(warning))
   134  		}
   135  		b, err := generateKubeYAML(libpod.ConvertV1PodToYAMLPod(po))
   136  		if err != nil {
   137  			return nil, err
   138  		}
   139  
   140  		podContent = append(podContent, b)
   141  		if options.Service {
   142  			svc, err := libpod.GenerateKubeServiceFromV1Pod(po, []k8sAPI.ServicePort{})
   143  			if err != nil {
   144  				return nil, err
   145  			}
   146  			b, err := generateKubeYAML(svc)
   147  			if err != nil {
   148  				return nil, err
   149  			}
   150  			content = append(content, b)
   151  		}
   152  	}
   153  
   154  	// Content order is based on helm install order (secret, persistentVolumeClaim, service, pod).
   155  	content = append(content, podContent...)
   156  
   157  	// Generate kube YAML file from all kube kinds.
   158  	k, err := generateKubeOutput(content)
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	return &entities.GenerateKubeReport{Reader: bytes.NewReader(k)}, nil
   164  }
   165  
   166  // getKubePods returns kube pod and service YAML files from podman pods.
   167  func getKubePods(ctx context.Context, pods []*libpod.Pod, getService bool) ([][]byte, [][]byte, error) {
   168  	pos := [][]byte{}
   169  	svcs := [][]byte{}
   170  
   171  	for _, p := range pods {
   172  		po, sp, err := p.GenerateForKube(ctx)
   173  		if err != nil {
   174  			return nil, nil, err
   175  		}
   176  
   177  		b, err := generateKubeYAML(po)
   178  		if err != nil {
   179  			return nil, nil, err
   180  		}
   181  		pos = append(pos, b)
   182  
   183  		if getService {
   184  			svc, err := libpod.GenerateKubeServiceFromV1Pod(po, sp)
   185  			if err != nil {
   186  				return nil, nil, err
   187  			}
   188  			b, err := generateKubeYAML(svc)
   189  			if err != nil {
   190  				return nil, nil, err
   191  			}
   192  			svcs = append(svcs, b)
   193  		}
   194  	}
   195  
   196  	return pos, svcs, nil
   197  }
   198  
   199  // getKubePVCs returns kube persistent volume claim YAML files from podman volumes.
   200  func getKubePVCs(volumes []*libpod.Volume) ([][]byte, error) {
   201  	pvs := [][]byte{}
   202  
   203  	for _, v := range volumes {
   204  		b, err := generateKubeYAML(v.GenerateForKube())
   205  		if err != nil {
   206  			return nil, err
   207  		}
   208  		pvs = append(pvs, b)
   209  	}
   210  
   211  	return pvs, nil
   212  }
   213  
   214  // generateKubeYAML marshalls a kube kind into a YAML file.
   215  func generateKubeYAML(kubeKind interface{}) ([]byte, error) {
   216  	b, err := yaml.Marshal(kubeKind)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  
   221  	return b, nil
   222  }
   223  
   224  // generateKubeOutput generates kube YAML file containing multiple kube kinds.
   225  func generateKubeOutput(content [][]byte) ([]byte, error) {
   226  	output := make([]byte, 0)
   227  
   228  	header := `# Save the output of this file and use kubectl create -f to import
   229  # it into Kubernetes.
   230  #
   231  # Created with podman-%s
   232  `
   233  	podmanVersion, err := define.GetVersion()
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  
   238  	// Add header to kube YAML file.
   239  	output = append(output, []byte(fmt.Sprintf(header, podmanVersion.Version))...)
   240  
   241  	// kube generate order is based on helm install order (secret, persistentVolume, service, pod...).
   242  	// Add kube kinds.
   243  	for i, b := range content {
   244  		if i != 0 {
   245  			output = append(output, []byte("---\n")...)
   246  		}
   247  
   248  		output = append(output, b...)
   249  	}
   250  
   251  	return output, nil
   252  }