Repository: PrefectHQ/prefect

Issue:
`agent install` w/ `--resource-manager` fails on imagePullSecrets map
## Description
`map: map[] does not contain declared merge key: name` when running `prefect agent install --resource-manager | kubectl apply --namespace=bleh -f -`



## Expected Behavior
It should have applied fine because without `--resource-manager` it works well




## Reproduction
If you remove
```
      imagePullSecrets:
      - {name: ''}
```
from the YAML it works. 

Solution: will keep out the imagePullSecrets block


## Environment
N/A




Discussion:
FYI I still see this behavior running on master after #1469 :
```
(model) ➜  model git:(prefect) ✗ prefect agent install kubernetes -t TOKEN --resource-manager
apiVersion: apps/v1
kind: Deployment
metadata:
  labels: {app: prefect-agent}
  name: prefect-agent
spec:
  replicas: 1
  selector:
    matchLabels: {app: prefect-agent}
  template:
    metadata:
      labels: {app: prefect-agent}
    spec:
      containers:
      - args: [prefect agent start kubernetes]
        command: [/bin/bash, -c]
        env:
        - {name: PREFECT__CLOUD__AGENT__AUTH_TOKEN, value: TOKEN}
        - {name: PREFECT__CLOUD__API, value: 'https://api.prefect.io'}
        - {name: NAMESPACE, value: default}
        - {name: IMAGE_PULL_SECRETS, value: ''}
        image: prefecthq/prefect:latest
        imagePullPolicy: Always
        livenessProbe:
          exec:
            command: [python, -c, from prefect.agent.kubernetes.agent import check_heartbeat;
                check_heartbeat()]
          failureThreshold: 2
          initialDelaySeconds: 40
          periodSeconds: 40
        name: agent
        resources:
          limits: {cpu: 100m, memory: 128Mi}
      - args: [python -c 'from prefect.agent.kubernetes import ResourceManager; ResourceManager().start()']
        command: [/bin/bash, -c]
        env:
        - {name: PREFECT__CLOUD__AGENT__AUTH_TOKEN, value: TOKEN}
        - {name: PREFECT__CLOUD__API, value: 'https://api.prefect.io'}
        - {name: PREFECT__CLOUD__AGENT__RESOURCE_MANAGER__LOOP_INTERVAL, value: '60'}
        - {name: NAMESPACE, value: default}
        image: prefecthq/prefect:latest
        imagePullPolicy: Always
        name: resource-manager
        resources:
          limits: {cpu: 100m, memory: 128Mi}
      imagePullSecrets:
      - {name: ''}
```
removing the last block still fixes the issue
Interesting, I'll reopen and address
@bnaul I was unable to reproduce this issue:
```
prefect on  master
➜ prefect agent install kubernetes -t TOKEN --resource-manager | kubectl apply -f -
deployment.apps/prefect-agent created
```

I also tested putting it into a yaml file:
```
➜ prefect agent install kubernetes -t TOKEN --resource-manager > test.yaml
➜ kubectl apply -f test.yaml
deployment.apps/prefect-agent created
```

I can adjust the code to remove the block entirely if not provided which would solve the problem but I'm curious as to why it works on my setup

Resolving patch:
diff --git a/src/prefect/agent/kubernetes/agent.py b/src/prefect/agent/kubernetes/agent.py
--- a/src/prefect/agent/kubernetes/agent.py
+++ b/src/prefect/agent/kubernetes/agent.py
@@ -124,6 +124,7 @@ def generate_deployment_yaml(
         token: str = None,
         api: str = None,
         namespace: str = None,
+        image_pull_secrets: str = None,
         resource_manager_enabled: bool = False,
     ) -> str:
 
@@ -143,6 +144,7 @@ def generate_deployment_yaml(
         agent_env[1]["value"] = api
         agent_env[2]["value"] = namespace
 
+        # Populate resource manager if requested
         if resource_manager_enabled:
             resource_manager_env = deployment["spec"]["template"]["spec"]["containers"][
                 1
@@ -154,6 +156,14 @@ def generate_deployment_yaml(
         else:
             del deployment["spec"]["template"]["spec"]["containers"][1]
 
+        # Populate image pull secrets if provided
+        if image_pull_secrets:
+            agent_env = deployment["spec"]["template"]["spec"]["imagePullSecrets"][0][
+                "name"
+            ] = image_pull_secrets
+        else:
+            del deployment["spec"]["template"]["spec"]["imagePullSecrets"]
+
         return yaml.safe_dump(deployment)
 
     def heartbeat(self) -> None:
diff --git a/src/prefect/cli/agent.py b/src/prefect/cli/agent.py
--- a/src/prefect/cli/agent.py
+++ b/src/prefect/cli/agent.py
@@ -96,25 +96,33 @@ def start(name, token, no_pull, base_url):
     help="Agent namespace to launch workloads.",
     hidden=True,
 )
+@click.option(
+    "--image-pull-secrets",
+    "-i",
+    required=False,
+    help="Name of image pull secrets to use for workloads.",
+    hidden=True,
+)
 @click.option(
     "--resource-manager", is_flag=True, help="Enable resource manager.", hidden=True
 )
-def install(name, token, api, namespace, resource_manager):
+def install(name, token, api, namespace, image_pull_secrets, resource_manager):
     """
     Install an agent. Outputs configuration text which can be used to install on various
     platforms.
 
     \b
     Arguments:
-        name                TEXT    The name of an agent to start (e.g. `kubernetes`)
-                                    Defaults to `kubernetes`
+        name                        TEXT    The name of an agent to start (e.g. `kubernetes`)
+                                            Defaults to `kubernetes`
 
     \b
     Options:
-        --token, -t         TEXT    A Prefect Cloud API token
-        --api, -a           TEXT    A Prefect Cloud API URL
-        --namespace, -n     TEXT    Agent namespace to launch workloads
-        --resource-manager          Enable resource manager on install
+        --token, -t                 TEXT    A Prefect Cloud API token
+        --api, -a                   TEXT    A Prefect Cloud API URL
+        --namespace, -n             TEXT    Agent namespace to launch workloads
+        --image-pull-secrets, -i    TEXT    Name of image pull secrets to use for workloads
+        --resource-manager                  Enable resource manager on install
     """
 
     supported_agents = {"kubernetes": "prefect.agent.kubernetes.KubernetesAgent"}
@@ -129,6 +137,7 @@ def install(name, token, api, namespace, resource_manager):
         token=token,
         api=api,
         namespace=namespace,
+        image_pull_secrets=image_pull_secrets,
         resource_manager_enabled=resource_manager,
     )
     click.echo(deployment)


Test patch:
diff --git a/tests/agent/test_k8s_agent.py b/tests/agent/test_k8s_agent.py
--- a/tests/agent/test_k8s_agent.py
+++ b/tests/agent/test_k8s_agent.py
@@ -218,6 +218,44 @@ def test_k8s_agent_generate_deployment_yaml_no_resource_manager(
     assert len(deployment["spec"]["template"]["spec"]["containers"]) == 1
 
 
+def test_k8s_agent_generate_deployment_yaml_no_image_pull_secrets(
+    monkeypatch, runner_token
+):
+    k8s_config = MagicMock()
+    monkeypatch.setattr("kubernetes.config", k8s_config)
+
+    agent = KubernetesAgent()
+    deployment = agent.generate_deployment_yaml(
+        token="test_token", api="test_api", namespace="test_namespace"
+    )
+
+    deployment = yaml.safe_load(deployment)
+
+    assert deployment["spec"]["template"]["spec"].get("imagePullSecrets") is None
+
+
+def test_k8s_agent_generate_deployment_yaml_contains_image_pull_secrets(
+    monkeypatch, runner_token
+):
+    k8s_config = MagicMock()
+    monkeypatch.setattr("kubernetes.config", k8s_config)
+
+    agent = KubernetesAgent()
+    deployment = agent.generate_deployment_yaml(
+        token="test_token",
+        api="test_api",
+        namespace="test_namespace",
+        image_pull_secrets="secrets",
+    )
+
+    deployment = yaml.safe_load(deployment)
+
+    assert (
+        deployment["spec"]["template"]["spec"]["imagePullSecrets"][0]["name"]
+        == "secrets"
+    )
+
+
 def test_k8s_agent_heartbeat_creates_file(monkeypatch, runner_token):
     k8s_config = MagicMock()
     monkeypatch.setattr("kubernetes.config", k8s_config)
diff --git a/tests/cli/test_agent.py b/tests/cli/test_agent.py
--- a/tests/cli/test_agent.py
+++ b/tests/cli/test_agent.py
@@ -104,6 +104,8 @@ def test_agent_install_passes_args():
             "--namespace",
             "TEST_NAMESPACE",
             "--resource-manager",
+            "--image-pull-secrets",
+            "secret-test",
         ],
     )
     assert result.exit_code == 0
@@ -111,6 +113,7 @@ def test_agent_install_passes_args():
     assert "TEST_API" in result.output
     assert "TEST_NAMESPACE" in result.output
     assert "resource-manager" in result.output
+    assert "secret-test" in result.output
 
 
 def test_agent_install_no_resource_manager():
@@ -125,6 +128,8 @@ def test_agent_install_no_resource_manager():
             "TEST_API",
             "--namespace",
             "TEST_NAMESPACE",
+            "--image-pull-secrets",
+            "secret-test",
         ],
     )
     assert result.exit_code == 0
@@ -132,3 +137,4 @@ def test_agent_install_no_resource_manager():
     assert "TEST_API" in result.output
     assert "TEST_NAMESPACE" in result.output
     assert not "resource-manager" in result.output
+    assert "secret-test" in result.output