Skip to content

Commit

Permalink
Merge pull request #19579 from danishprakash/generate-daemonset-support
Browse files Browse the repository at this point in the history
kube: add DaemonSet support for generate
  • Loading branch information
openshift-merge-robot authored Sep 12, 2023
2 parents 91f3f3a + cdcf18b commit 7da91ad
Show file tree
Hide file tree
Showing 10 changed files with 435 additions and 5 deletions.
2 changes: 1 addition & 1 deletion cmd/podman/kube/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var (
playOptions = playKubeOptionsWrapper{}
playDescription = `Reads in a structured file of Kubernetes YAML.
Creates pods or volumes based on the Kubernetes kind described in the YAML. Supported kinds are Pods, Deployments and PersistentVolumeClaims.`
Creates pods or volumes based on the Kubernetes kind described in the YAML. Supported kinds are Pods, Deployments, DaemonSets and PersistentVolumeClaims.`

playCmd = &cobra.Command{
Use: "play [options] KUBEFILE|-",
Expand Down
12 changes: 12 additions & 0 deletions docs/kubernetes_support.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,15 @@ Note: **N/A** means that the option cannot be supported in a single-node Podman
| revisionHistoryLimit | no |
| progressDeadlineSeconds | no |
| paused | no |

## DaemonSet Fields

| Field | Support |
|-----------------------------------------|-------------------------------------------------------|
| selector ||
| template ||
| minReadySeconds | no |
| strategy\.type | no |
| strategy\.rollingUpdate\.maxSurge | no |
| strategy\.rollingUpdate\.maxUnavailable | no |
| revisionHistoryLimit | no |
6 changes: 4 additions & 2 deletions docs/source/markdown/podman-kube-generate.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Note that the generated Kubernetes YAML file can be used to re-run the deploymen

Note that if the pod being generated was created with the **--infra-name** flag set, then the generated kube yaml will have the **io.podman.annotations.infra.name** set where the value is the name of the infra container set by the user.

Also note that both Deployment and DaemonSet can only have `restartPolicy` set to `Always`.

## OPTIONS

#### **--filename**, **-f**=*filename*
Expand All @@ -54,9 +56,9 @@ Note: this can only be set with the option `--type=deployment`.

Generate a Kubernetes service object in addition to the Pods. Used to generate a Service specification for the corresponding Pod output. In particular, if the object has portmap bindings, the service specification includes a NodePort declaration to expose the service. A random port is assigned by Podman in the specification.

#### **--type**, **-t**=*pod | deployment*
#### **--type**, **-t**=*pod* | *deployment* | *daemonset*

The Kubernetes kind to generate in the YAML file. Currently, the only supported Kubernetes specifications are `Pod` and `Deployment`. By default, the `Pod` specification is generated.
The Kubernetes kind to generate in the YAML file. Currently, the only supported Kubernetes specifications are `Pod`, `Deployment` and `DaemonSet`. By default, the `Pod` specification is generated.

## EXAMPLES

Expand Down
1 change: 1 addition & 0 deletions docs/source/markdown/podman-kube-play.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Currently, the supported Kubernetes kinds are:
- PersistentVolumeClaim
- ConfigMap
- Secret
- DaemonSet

`Kubernetes Pods or Deployments`

Expand Down
2 changes: 2 additions & 0 deletions libpod/define/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ const (
K8sKindPod = "pod"
// A Deployment kube yaml spec
K8sKindDeployment = "deployment"
// A DaemonSet kube yaml spec
K8sKindDaemonSet = "daemonset"
)
77 changes: 77 additions & 0 deletions libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,61 @@ func (p *Pod) getInfraContainer() (*Container, error) {
return p.runtime.GetContainer(infraID)
}

func GenerateForKubeDaemonSet(ctx context.Context, pod *YAMLPod, options entities.GenerateKubeOptions) (*YAMLDaemonSet, error) {
// Restart policy for DaemonSets can only be set to Always
if !(pod.Spec.RestartPolicy == "" || pod.Spec.RestartPolicy == v1.RestartPolicyAlways) {
return nil, fmt.Errorf("k8s DaemonSets can only have restartPolicy set to Always")
}

// Error out if the user tries to set replica count
if options.Replicas > 1 {
return nil, fmt.Errorf("k8s DaemonSets don't allow setting replicas")
}

// Create label map that will be added to podSpec and DaemonSet metadata
// The matching label lets the daemonset know which pod to manage
appKey := "app"
matchLabels := map[string]string{appKey: pod.Name}
// Add the key:value (app:pod-name) to the podSpec labels
if pod.Labels == nil {
pod.Labels = matchLabels
} else {
pod.Labels[appKey] = pod.Name
}

depSpec := YAMLDaemonSetSpec{
DaemonSetSpec: v1.DaemonSetSpec{
Selector: &v12.LabelSelector{
MatchLabels: matchLabels,
},
},
Template: &YAMLPodTemplateSpec{
PodTemplateSpec: v1.PodTemplateSpec{
ObjectMeta: pod.ObjectMeta,
},
Spec: pod.Spec,
},
}

// Create the DaemonSet object
dep := YAMLDaemonSet{
DaemonSet: v1.DaemonSet{
ObjectMeta: v12.ObjectMeta{
Name: pod.Name + "-daemonset",
CreationTimestamp: pod.CreationTimestamp,
Labels: pod.Labels,
},
TypeMeta: v12.TypeMeta{
Kind: "DaemonSet",
APIVersion: "apps/v1",
},
},
Spec: &depSpec,
}

return &dep, nil
}

// GenerateForKubeDeployment returns a YAMLDeployment from a YAMLPod that is then used to create a kubernetes Deployment
// kind YAML.
func GenerateForKubeDeployment(ctx context.Context, pod *YAMLPod, options entities.GenerateKubeOptions) (*YAMLDeployment, error) {
Expand Down Expand Up @@ -262,6 +317,28 @@ type YAMLDeploymentSpec struct {
Strategy *v1.DeploymentStrategy `json:"strategy,omitempty"`
}

// YAMLDaemonSetSpec represents the same k8s API core DeploymentSpec with a small
// change and that is having Template as a pointer to YAMLPodTemplateSpec and Strategy
// as a pointer to k8s API core DaemonSetStrategy.
// Because Go doesn't omit empty struct and we want to omit Strategy and any fields in the Pod YAML
// if it's empty.
type YAMLDaemonSetSpec struct {
v1.DaemonSetSpec
Template *YAMLPodTemplateSpec `json:"template,omitempty"`
Strategy *v1.DaemonSetUpdateStrategy `json:"strategy,omitempty"`
}

// YAMLDaemonSet represents the same k8s API core DaemonSet with a small change
// and that is having Spec as a pointer to YAMLDaemonSetSpec and Status as a pointer to
// k8s API core DaemonSetStatus.
// Because Go doesn't omit empty struct and we want to omit Status and any fields in the DaemonSetSpec
// if it's empty.
type YAMLDaemonSet struct {
v1.DaemonSet
Spec *YAMLDaemonSetSpec `json:"spec,omitempty"`
Status *v1.DaemonSetStatus `json:"status,omitempty"`
}

// YAMLDeployment represents the same k8s API core Deployment with a small change
// and that is having Spec as a pointer to YAMLDeploymentSpec and Status as a pointer to
// k8s API core DeploymentStatus.
Expand Down
24 changes: 22 additions & 2 deletions pkg/domain/infra/abi/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,24 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
return nil, err
}
typeContent = append(typeContent, b)
case define.K8sKindDaemonSet:
dep, err := libpod.GenerateForKubeDaemonSet(ctx, libpod.ConvertV1PodToYAMLPod(po), options)
if err != nil {
return nil, err
}
b, err := generateKubeYAML(dep)
if err != nil {
return nil, err
}
typeContent = append(typeContent, b)
case define.K8sKindPod:
b, err := generateKubeYAML(libpod.ConvertV1PodToYAMLPod(po))
if err != nil {
return nil, err
}
typeContent = append(typeContent, b)
default:
return nil, fmt.Errorf("invalid generation type - only pods and deployments are currently supported")
return nil, fmt.Errorf("invalid generation type - only pods, deployments and daemonsets are currently supported: %+v", options.Type)
}

if options.Service {
Expand Down Expand Up @@ -289,14 +299,24 @@ func getKubePods(ctx context.Context, pods []*libpod.Pod, options entities.Gener
return nil, nil, err
}
out = append(out, b)
case define.K8sKindDaemonSet:
dep, err := libpod.GenerateForKubeDaemonSet(ctx, libpod.ConvertV1PodToYAMLPod(po), options)
if err != nil {
return nil, nil, err
}
b, err := generateKubeYAML(dep)
if err != nil {
return nil, nil, err
}
out = append(out, b)
case define.K8sKindPod:
b, err := generateKubeYAML(libpod.ConvertV1PodToYAMLPod(po))
if err != nil {
return nil, nil, err
}
out = append(out, b)
default:
return nil, nil, fmt.Errorf("invalid generation type - only pods and deployments are currently supported")
return nil, nil, fmt.Errorf("invalid generation type - only pods, deployments and daemonsets are currently supported")
}

if options.Service {
Expand Down
Loading

0 comments on commit 7da91ad

Please sign in to comment.