Repository: knative/client
Pull request #1277 (2021-03-31 23:59:35)

Update OWNERS_ALIASES to match autogen in community
See https://github.com/knative/community/pull/552 for the addition of groups/full OWNERS_ALIASES that will be synced.

This is a preparatory PR for landing OWNERS_ALIASES automation across the Knative org (alternative to the CODEOWNERS changes in knative-sandbox).

If this seems to be expanding permissions or otherwise likely to cause a problem, `/hold` this PR and comment here or on https://github.com/knative/community/pull/552.


knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **navidshaikh** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @navidshaikh` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative%2Fclient).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/knative/client/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["navidshaikh"]} -->
knative-prow-robot: @evankanderson: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
knative-prow-robot: @evankanderson: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-build-tests/1377410291268063232) | `/test pull-knative-client-build-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1277). [Your PR dashboard](https://gubernator.knative.dev/pr/evankanderson).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-prow-robot: @evankanderson: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-build-tests/1377410291268063232) | `/test pull-knative-client-build-tests`
pull-knative-client-go-coverage | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-go-coverage/1377410291335172096) | `/test pull-knative-client-go-coverage`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1277). [Your PR dashboard](https://gubernator.knative.dev/pr/evankanderson).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-prow-robot: @evankanderson: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-build-tests/1377410291268063232) | `/test pull-knative-client-build-tests`
pull-knative-client-go-coverage | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-go-coverage/1377410291335172096) | `/test pull-knative-client-go-coverage`
pull-knative-client-unit-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-unit-tests/1377410291289034752) | `/test pull-knative-client-unit-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1277). [Your PR dashboard](https://gubernator.knative.dev/pr/evankanderson).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-prow-robot: @evankanderson: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-build-tests/1377410291268063232) | `/test pull-knative-client-build-tests`
pull-knative-client-go-coverage | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-go-coverage/1377410291335172096) | `/test pull-knative-client-go-coverage`
pull-knative-client-unit-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-unit-tests/1377410291289034752) | `/test pull-knative-client-unit-tests`
pull-knative-client-integration-tests-latest-release | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-integration-tests-latest-release/1377410291360337920) | `/test pull-knative-client-integration-tests-latest-release`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1277). [Your PR dashboard](https://gubernator.knative.dev/pr/evankanderson).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-prow-robot: @evankanderson: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-build-tests/1377410291268063232) | `/test pull-knative-client-build-tests`
pull-knative-client-go-coverage | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-go-coverage/1377410291335172096) | `/test pull-knative-client-go-coverage`
pull-knative-client-unit-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-unit-tests/1377410291289034752) | `/test pull-knative-client-unit-tests`
pull-knative-client-integration-tests-latest-release | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-integration-tests-latest-release/1377410291360337920) | `/test pull-knative-client-integration-tests-latest-release`
pull-knative-client-integration-tests | e66284ca3d1277fb8005fa0b1e462384d5af137a | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1277/pull-knative-client-integration-tests/1377410291318394880) | `/test pull-knative-client-integration-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1277). [Your PR dashboard](https://gubernator.knative.dev/pr/evankanderson).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->

Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index d5838c75..3e016e58 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -40,6 +40,11 @@
 | 🎁
 | Add context.Context parameter to API function
 | https://github.com/knative/client/pull/1274[#1274]
+
+| 🎁
+| Add `kn domain` commands to manage DomainMapping
+| https://github.com/knative/client/pull/1267[#1267]
+
 |===
 
 ## v0.21.0 (2021-02-23)
diff --git a/OWNERS b/OWNERS
index 58bc5f70..42f8002e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,7 +1,5 @@
 approvers:
-- maximilien
-- dsimansk
-- client-wg-leads
-- toc
+- client-writers
+- technical-oversight-committee
 reviewers:
-- itsmurugappan
+- client-reviewers
diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES
index 94adad0c..1ab0a9a6 100644
--- a/OWNERS_ALIASES
+++ b/OWNERS_ALIASES
@@ -12,7 +12,11 @@ aliases:
   client-wg-leads:
   - navidshaikh
   - rhuss
+  client-reviewers:
+  - itsmurugappan
   client-writers:
+  - dsimansk
+  - maximilien
   - navidshaikh
   - rhuss
   conformance-wg-leads:
diff --git a/docs/cmd/kn.md b/docs/cmd/kn.md
index ba6759ed..6c57cee8 100644
--- a/docs/cmd/kn.md
+++ b/docs/cmd/kn.md
@@ -24,6 +24,7 @@ kn is the command line interface for managing Knative Serving and Eventing resou
 * [kn broker](kn_broker.md)	 - Manage message brokers
 * [kn channel](kn_channel.md)	 - Manage event channels
 * [kn completion](kn_completion.md)	 - Output shell completion code
+* [kn domain](kn_domain.md)	 - Manage domain mappings
 * [kn options](kn_options.md)	 - Print the list of flags inherited by all commands
 * [kn plugin](kn_plugin.md)	 - Manage kn plugins
 * [kn revision](kn_revision.md)	 - Manage service revisions
diff --git a/docs/cmd/kn_domain.md b/docs/cmd/kn_domain.md
new file mode 100644
index 00000000..d04e5848
--- /dev/null
+++ b/docs/cmd/kn_domain.md
@@ -0,0 +1,33 @@
+## kn domain
+
+Manage domain mappings
+
+```
+kn domain COMMAND
+```
+
+### Options
+
+```
+  -h, --help   help for domain
+```
+
+### Options inherited from parent commands
+
+```
+      --cluster string      name of the kubeconfig cluster to use
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --context string      name of the kubeconfig context to use
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn](kn.md)	 - kn manages Knative Serving and Eventing resources
+* [kn domain create](kn_domain_create.md)	 - Create a domain mapping
+* [kn domain delete](kn_domain_delete.md)	 - Delete a domain mapping
+* [kn domain describe](kn_domain_describe.md)	 - Show details of a domain mapping
+* [kn domain list](kn_domain_list.md)	 - List domain mappings
+* [kn domain update](kn_domain_update.md)	 - Update a domain mapping
+
diff --git a/docs/cmd/kn_domain_create.md b/docs/cmd/kn_domain_create.md
new file mode 100644
index 00000000..b46b24cf
--- /dev/null
+++ b/docs/cmd/kn_domain_create.md
@@ -0,0 +1,38 @@
+## kn domain create
+
+Create a domain mapping
+
+```
+kn domain create NAME
+```
+
+### Examples
+
+```
+
+  # Create a domain mappings 'hello.example.com' for Knative service 'hello'
+  kn domain create hello.example.com --ref hello
+```
+
+### Options
+
+```
+  -h, --help               help for create
+  -n, --namespace string   Specify the namespace to operate in.
+      --ref string         Addressable target reference for Domain Mapping. You can specify a Knative service, a Knative route. Examples: '--ref' ksvc:hello' or simply '--ref hello' for a Knative service 'hello', '--ref' kroute:hello' for a Knative route 'hello'. '--ref ksvc:mysvc:mynamespace' for a Knative service 'mysvc' in another namespace 'mynamespace', If a prefix is not provided, it is considered as a Knative service in the current namespace. If referring to a Knative service in another namespace, 'ksvc:name:namespace' combination must be provided explicitly.
+```
+
+### Options inherited from parent commands
+
+```
+      --cluster string      name of the kubeconfig cluster to use
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --context string      name of the kubeconfig context to use
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn domain](kn_domain.md)	 - Manage domain mappings
+
diff --git a/docs/cmd/kn_domain_delete.md b/docs/cmd/kn_domain_delete.md
new file mode 100644
index 00000000..a7d4d781
--- /dev/null
+++ b/docs/cmd/kn_domain_delete.md
@@ -0,0 +1,37 @@
+## kn domain delete
+
+Delete a domain mapping
+
+```
+kn domain delete NAME
+```
+
+### Examples
+
+```
+
+  # Delete domain mappings 'hello.example.com'
+  kn domain delete hello.example.com
+```
+
+### Options
+
+```
+  -h, --help               help for delete
+  -n, --namespace string   Specify the namespace to operate in.
+```
+
+### Options inherited from parent commands
+
+```
+      --cluster string      name of the kubeconfig cluster to use
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --context string      name of the kubeconfig context to use
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn domain](kn_domain.md)	 - Manage domain mappings
+
diff --git a/docs/cmd/kn_domain_describe.md b/docs/cmd/kn_domain_describe.md
new file mode 100644
index 00000000..cd51a969
--- /dev/null
+++ b/docs/cmd/kn_domain_describe.md
@@ -0,0 +1,33 @@
+## kn domain describe
+
+Show details of a domain mapping
+
+```
+kn domain describe NAME
+```
+
+### Options
+
+```
+      --allow-missing-template-keys   If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true)
+  -h, --help                          help for describe
+  -n, --namespace string              Specify the namespace to operate in.
+  -o, --output string                 Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file|url.
+      --template string               Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
+  -v, --verbose                       More output.
+```
+
+### Options inherited from parent commands
+
+```
+      --cluster string      name of the kubeconfig cluster to use
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --context string      name of the kubeconfig context to use
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn domain](kn_domain.md)	 - Manage domain mappings
+
diff --git a/docs/cmd/kn_domain_list.md b/docs/cmd/kn_domain_list.md
new file mode 100644
index 00000000..b256a562
--- /dev/null
+++ b/docs/cmd/kn_domain_list.md
@@ -0,0 +1,45 @@
+## kn domain list
+
+List domain mappings
+
+```
+kn domain list
+```
+
+### Examples
+
+```
+
+  # List all domain mappings
+  kn domain list
+
+  # List all domain mappings in JSON output format
+  kn revision list -o json
+```
+
+### Options
+
+```
+  -A, --all-namespaces                If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.
+      --allow-missing-template-keys   If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true)
+  -h, --help                          help for list
+  -n, --namespace string              Specify the namespace to operate in.
+      --no-headers                    When using the default output format, don't print headers (default: print headers).
+  -o, --output string                 Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
+      --template string               Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
+```
+
+### Options inherited from parent commands
+
+```
+      --cluster string      name of the kubeconfig cluster to use
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --context string      name of the kubeconfig context to use
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn domain](kn_domain.md)	 - Manage domain mappings
+
diff --git a/docs/cmd/kn_domain_update.md b/docs/cmd/kn_domain_update.md
new file mode 100644
index 00000000..7611277b
--- /dev/null
+++ b/docs/cmd/kn_domain_update.md
@@ -0,0 +1,38 @@
+## kn domain update
+
+Update a domain mapping
+
+```
+kn domain update NAME
+```
+
+### Examples
+
+```
+
+  # Update a domain mappings 'hello.example.com' for Knative service 'hello'
+  kn domain create hello.example.com --refFlags hello
+```
+
+### Options
+
+```
+  -h, --help               help for update
+  -n, --namespace string   Specify the namespace to operate in.
+      --ref string         Addressable target reference for Domain Mapping. You can specify a Knative service, a Knative route. Examples: '--ref' ksvc:hello' or simply '--ref hello' for a Knative service 'hello', '--ref' kroute:hello' for a Knative route 'hello'. '--ref ksvc:mysvc:mynamespace' for a Knative service 'mysvc' in another namespace 'mynamespace', If a prefix is not provided, it is considered as a Knative service in the current namespace. If referring to a Knative service in another namespace, 'ksvc:name:namespace' combination must be provided explicitly.
+```
+
+### Options inherited from parent commands
+
+```
+      --cluster string      name of the kubeconfig cluster to use
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --context string      name of the kubeconfig context to use
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn domain](kn_domain.md)	 - Manage domain mappings
+
diff --git a/go.mod b/go.mod
index 1db191a7..7111f858 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module knative.dev/client
 go 1.15
 
 require (
-	github.com/google/go-cmp v0.5.4
+	github.com/google/go-cmp v0.5.5
 	github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/mitchellh/mapstructure v1.3.1 // indirect
@@ -21,11 +21,11 @@ require (
 	k8s.io/cli-runtime v0.19.7
 	k8s.io/client-go v0.19.7
 	k8s.io/code-generator v0.19.7
-	knative.dev/eventing v0.21.1-0.20210312002228-3b427377abe0
-	knative.dev/hack v0.0.0-20210309141825-9b73a256fd9a
-	knative.dev/networking v0.0.0-20210311190926-430a689490e6
-	knative.dev/pkg v0.0.0-20210311174826-40488532be3f
-	knative.dev/serving v0.21.1-0.20210311225828-1583394c61cb
+	knative.dev/eventing v0.21.1-0.20210331231822-8f35d42544e0
+	knative.dev/hack v0.0.0-20210325223819-b6ab329907d3
+	knative.dev/networking v0.0.0-20210331064822-999a7708876c
+	knative.dev/pkg v0.0.0-20210331065221-952fdd90dbb0
+	knative.dev/serving v0.21.1-0.20210401115722-fc58a32f0ef6
 	sigs.k8s.io/yaml v1.2.0
 )
 
diff --git a/go.sum b/go.sum
index 6eaadb57..5784a4e8 100644
--- a/go.sum
+++ b/go.sum
@@ -350,6 +350,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-containerregistry v0.4.1-0.20210128200529-19c2b639fab1 h1:o2ykCuuhHeUwtzNg89pH2hi+821aqjLWkaREVR3ziTQ=
 github.com/google/go-containerregistry v0.4.1-0.20210128200529-19c2b639fab1/go.mod h1:GU9FUA/X9rd2cV3ZoUNaWihp27tki6/38EsVzL2Dyzc=
 github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20210129212729-5c4818de4025/go.mod h1:n9wRxRfKkHy6ZFyj0jJQHw11P+mGLnED4sqegwrXxDk=
@@ -641,6 +643,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
 github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
 github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
+github.com/prometheus/common v0.19.0 h1:Itb4+NjG9wRdkAWgVucbM/adyIXxEhbw0866e0uZE6A=
+github.com/prometheus/common v0.19.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -775,8 +779,8 @@ go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
 go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
-go.opencensus.io v0.22.6 h1:BdkrbWrzDlV9dnbzoP7sfN+dHheJ4J9JOaYxcUDL+ok=
-go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opentelemetry.io/otel v0.16.0/go.mod h1:e4GKElweB8W2gWUqbghw0B8t5MCTccc9212eNHnOHwA=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -1194,8 +1198,8 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
 google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs=
 google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
-google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1305,20 +1309,22 @@ k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K
 k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 h1:0T5IaWHO3sJTEmCP6mUlBvMukxPKUQWqiI/YuiBNMiQ=
 k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-knative.dev/caching v0.0.0-20210311181225-4b366c7a9f99/go.mod h1:OlAEAfCSUjHVetZp/hpMw3lzAGHfTEQyu2a5dgf/7Qo=
-knative.dev/eventing v0.21.1-0.20210312002228-3b427377abe0 h1:nd6yNE6L10abHfrrsVarMiirHke7tvqfP9uczfRCOIE=
-knative.dev/eventing v0.21.1-0.20210312002228-3b427377abe0/go.mod h1:k/F174UcHeY70F00RAExTv2/wg8yUR20EPYX3hlD3+8=
-knative.dev/hack v0.0.0-20210309141825-9b73a256fd9a h1:0UGKyvFzY1Czu0lP9+0IrJhwtKe2oNLI2GYa7MIQ5c0=
-knative.dev/hack v0.0.0-20210309141825-9b73a256fd9a/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/networking v0.0.0-20210311182125-f51c10d6fcf0/go.mod h1:dBcp0JBxATXsbCKK43cA6LxTricz4Ur3dPHataW5J64=
-knative.dev/networking v0.0.0-20210311190926-430a689490e6 h1:yuf+sPvbvjvQ2KBJrEORN/YPxuf3EIFD31z/jL4WfwU=
-knative.dev/networking v0.0.0-20210311190926-430a689490e6/go.mod h1:dBcp0JBxATXsbCKK43cA6LxTricz4Ur3dPHataW5J64=
-knative.dev/pkg v0.0.0-20210310173525-bbe0bb3eb1e0/go.mod h1:pn/vClSL/iCW40TlFR91EhtmMmsyPQR2V2LavDAOOMs=
-knative.dev/pkg v0.0.0-20210311174826-40488532be3f h1:WBgC84Ldkyvt+25osB1pfrNXH9LKoXvr3BptANZWvIE=
-knative.dev/pkg v0.0.0-20210311174826-40488532be3f/go.mod h1:pn/vClSL/iCW40TlFR91EhtmMmsyPQR2V2LavDAOOMs=
-knative.dev/reconciler-test v0.0.0-20210311161026-af80deacbe19/go.mod h1:BqljHB9eQj66yPyxOj62syip0ZZtiG0lw76XrtRe36M=
-knative.dev/serving v0.21.1-0.20210311225828-1583394c61cb h1:HX5EVjJJqIUoDAWmfulMnGvPFeKJkAC6GAuj9/y97Ig=
-knative.dev/serving v0.21.1-0.20210311225828-1583394c61cb/go.mod h1:5cO/KA08FzPBPuCa5CU2lEGZOP8V/zUgvoluuPcL1lQ=
+knative.dev/caching v0.0.0-20210331063521-5691bb38d441/go.mod h1:CfW7OVs7gzUXJj0OrIe8YlWEC4Qe0Avnq+5b81/Gw1s=
+knative.dev/eventing v0.21.1-0.20210331231822-8f35d42544e0 h1:hTZYXQgaWV3b2BVD7xjr6EMbwGETsnKs/VpgOfVkrZU=
+knative.dev/eventing v0.21.1-0.20210331231822-8f35d42544e0/go.mod h1:LOG7bh0eZQkbYANcnORwke6Yy6aUu62o8GeByaOFfRQ=
+knative.dev/hack v0.0.0-20210325223819-b6ab329907d3 h1:km0Rrh0T9/wA2pivQm1hqSPVwgNgGCHC2WNn3GakZmE=
+knative.dev/hack v0.0.0-20210325223819-b6ab329907d3/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
+knative.dev/hack/schema v0.0.0-20210325223819-b6ab329907d3/go.mod h1:ffjwmdcrH5vN3mPhO8RrF2KfNnbHeCE2C60A+2cv3U0=
+knative.dev/networking v0.0.0-20210331064822-999a7708876c h1:7ggsYXtltPHjbgxi76hg5g2eOtmg8KaBIP40XJsfMyA=
+knative.dev/networking v0.0.0-20210331064822-999a7708876c/go.mod h1:0V6M1AaWPL/MtQLuEx0NxiwDdtb8Y4b4f7P3C8sp0zo=
+knative.dev/pkg v0.0.0-20210329065222-9d92ea16c0d3/go.mod h1:PD5g8hUCXq6iR3tILjmZeJBvQfXGnHMPKryq54qHJhg=
+knative.dev/pkg v0.0.0-20210330162221-808d62257db6/go.mod h1:PD5g8hUCXq6iR3tILjmZeJBvQfXGnHMPKryq54qHJhg=
+knative.dev/pkg v0.0.0-20210331062321-6317ec6066f4/go.mod h1:PD5g8hUCXq6iR3tILjmZeJBvQfXGnHMPKryq54qHJhg=
+knative.dev/pkg v0.0.0-20210331065221-952fdd90dbb0 h1:z05hcB4br0qz7JdwIoUSTXLTF+7ThuJ+R6NFfXd1Y4Q=
+knative.dev/pkg v0.0.0-20210331065221-952fdd90dbb0/go.mod h1:PD5g8hUCXq6iR3tILjmZeJBvQfXGnHMPKryq54qHJhg=
+knative.dev/reconciler-test v0.0.0-20210329214021-2a67496462a4/go.mod h1:qLfJMHc0i9ENTSet/SUp/FcQm4QVfNTX8ZC//aVQN0M=
+knative.dev/serving v0.21.1-0.20210401115722-fc58a32f0ef6 h1:eXinNd46GLQHm5wAYX6Sqonj3E2dFZ+C48xumv1DjTg=
+knative.dev/serving v0.21.1-0.20210401115722-fc58a32f0ef6/go.mod h1:20yuZH4F7cvoovC2Pi1uQBoIbOjllapVSKDkWAXkItA=
 modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
 modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
 modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
diff --git a/pkg/dynamic/fake/fake.go b/pkg/dynamic/fake/fake.go
index 78dfc322..95caf7a3 100644
--- a/pkg/dynamic/fake/fake.go
+++ b/pkg/dynamic/fake/fake.go
@@ -15,6 +15,7 @@
 package fake
 
 import (
+	v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	dynamicfake "k8s.io/client-go/dynamic/fake"
@@ -28,7 +29,9 @@ import (
 // CreateFakeKnDynamicClient gives you a dynamic client for testing containing the given objects.
 func CreateFakeKnDynamicClient(testNamespace string, objects ...runtime.Object) dynamic.KnDynamicClient {
 	scheme := runtime.NewScheme()
+	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"}, &v1.Service{})
 	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "serving.knative.dev", Version: "v1", Kind: "Service"}, &servingv1.Service{})
+	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "serving.knative.dev", Version: "v1", Kind: "Route"}, &servingv1.Route{})
 	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1beta1", Kind: "Broker"}, &eventingv1beta1.Broker{})
 	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1beta1", Kind: "Subscription"}, &messagingv1beta1.Subscription{})
 	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "messaging.knative.dev", Version: "v1beta1", Kind: "Channel"}, &messagingv1beta1.Channel{})
diff --git a/pkg/kn/commands/domain/create.go b/pkg/kn/commands/domain/create.go
new file mode 100644
index 00000000..d240847e
--- /dev/null
+++ b/pkg/kn/commands/domain/create.go
@@ -0,0 +1,77 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	knerrors "knative.dev/client/pkg/errors"
+	"knative.dev/client/pkg/kn/commands"
+	clientv1alpha1 "knative.dev/client/pkg/serving/v1alpha1"
+)
+
+// NewDomainMappingCreateCommand to create event channels
+func NewDomainMappingCreateCommand(p *commands.KnParams) *cobra.Command {
+	var refFlags RefFlags
+	cmd := &cobra.Command{
+		Use:   "create NAME",
+		Short: "Create a domain mapping",
+		Example: `
+  # Create a domain mappings 'hello.example.com' for Knative service 'hello'
+  kn domain create hello.example.com --ref hello`,
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("'kn domain create' requires the domain name given as single argument")
+			}
+			name := args[0]
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			dynamicClient, err := p.NewDynamicClient(namespace)
+			if err != nil {
+				return err
+			}
+			reference, err := refFlags.Resolve(cmd.Context(), dynamicClient, namespace)
+			if err != nil {
+				return err
+			}
+
+			builder := clientv1alpha1.NewDomainMappingBuilder(name).
+				Namespace(namespace).
+				Reference(*reference)
+
+			client, err := p.NewServingV1alpha1Client(namespace)
+			if err != nil {
+				return err
+			}
+			err = client.CreateDomainMapping(cmd.Context(), builder.Build())
+			if err != nil {
+				return knerrors.GetError(err)
+			}
+
+			fmt.Fprintf(cmd.OutOrStdout(), "Domain mapping '%s' created in namespace '%s'.\n", name, namespace)
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	refFlags.Add(cmd)
+	cmd.MarkFlagRequired("ref")
+	return cmd
+}
diff --git a/pkg/kn/commands/domain/delete.go b/pkg/kn/commands/domain/delete.go
new file mode 100644
index 00000000..7a68a923
--- /dev/null
+++ b/pkg/kn/commands/domain/delete.go
@@ -0,0 +1,62 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	knerrors "knative.dev/client/pkg/errors"
+	"knative.dev/client/pkg/kn/commands"
+)
+
+// NewDomainMappingDeleteCommand to create event channels
+func NewDomainMappingDeleteCommand(p *commands.KnParams) *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "delete NAME",
+		Short: "Delete a domain mapping",
+		Example: `
+  # Delete domain mappings 'hello.example.com'
+  kn domain delete hello.example.com`,
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("'kn domain delete' requires the domain name given as single argument")
+			}
+			name := args[0]
+
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			client, err := p.NewServingV1alpha1Client(namespace)
+			if err != nil {
+				return err
+			}
+
+			err = client.DeleteDomainMapping(cmd.Context(), name)
+			if err != nil {
+				return knerrors.GetError(err)
+			}
+
+			fmt.Fprintf(cmd.OutOrStdout(), "Domain mapping '%s' deleted in namespace '%s'.\n", name, namespace)
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	return cmd
+}
diff --git a/pkg/kn/commands/domain/describe.go b/pkg/kn/commands/domain/describe.go
new file mode 100644
index 00000000..9941bdf7
--- /dev/null
+++ b/pkg/kn/commands/domain/describe.go
@@ -0,0 +1,95 @@
+// Copyright © 2019 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"strings"
+
+	"github.com/spf13/cobra"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
+
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/printers"
+	"knative.dev/serving/pkg/apis/serving/v1alpha1"
+)
+
+// NewDomainMappingDescribeCommand represents 'kn route describe' command
+func NewDomainMappingDescribeCommand(p *commands.KnParams) *cobra.Command {
+	// For machine readable output
+	machineReadablePrintFlags := genericclioptions.NewPrintFlags("")
+	cmd := &cobra.Command{
+		Use:   "describe NAME",
+		Short: "Show details of a domain mapping",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			if len(args) != 1 {
+				return errors.New("'kn domain describe' requires name of the domain mapping as single argument")
+			}
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			client, err := p.NewServingV1alpha1Client(namespace)
+			if err != nil {
+				return err
+			}
+
+			domainMapping, err := client.GetDomainMapping(cmd.Context(), args[0])
+			if err != nil {
+				return err
+			}
+
+			if machineReadablePrintFlags.OutputFlagSpecified() {
+				if strings.ToLower(*machineReadablePrintFlags.OutputFormat) == "url" {
+					fmt.Fprintf(cmd.OutOrStdout(), "%s\n", domainMapping.Status.URL)
+					return nil
+				}
+				printer, err := machineReadablePrintFlags.ToPrinter()
+				if err != nil {
+					return err
+				}
+				return printer.PrintObj(domainMapping, cmd.OutOrStdout())
+			}
+			printDetails, err := cmd.Flags().GetBool("verbose")
+			if err != nil {
+				return err
+			}
+			return describe(cmd.OutOrStdout(), domainMapping, printDetails)
+		},
+	}
+	flags := cmd.Flags()
+	commands.AddNamespaceFlags(flags, false)
+	machineReadablePrintFlags.AddFlags(cmd)
+	cmd.Flag("output").Usage = fmt.Sprintf("Output format. One of: %s.", strings.Join(append(machineReadablePrintFlags.AllowedFormats(), "url"), "|"))
+	flags.BoolP("verbose", "v", false, "More output.")
+	return cmd
+}
+
+func describe(w io.Writer, domainMapping *v1alpha1.DomainMapping, printDetails bool) error {
+	dw := printers.NewPrefixWriter(w)
+	commands.WriteMetadata(dw, &domainMapping.ObjectMeta, printDetails)
+	dw.WriteLine()
+	dw.WriteAttribute("URL", domainMapping.Status.URL.String())
+	dw.WriteAttribute("Service", domainMapping.Spec.Ref.Name)
+	dw.WriteLine()
+	commands.WriteConditions(dw, domainMapping.Status.Conditions, printDetails)
+	if err := dw.Flush(); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/pkg/kn/commands/domain/domain.go b/pkg/kn/commands/domain/domain.go
new file mode 100644
index 00000000..da8aba7d
--- /dev/null
+++ b/pkg/kn/commands/domain/domain.go
@@ -0,0 +1,111 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	"github.com/spf13/cobra"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	clientdynamic "knative.dev/client/pkg/dynamic"
+	"knative.dev/client/pkg/kn/commands"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+)
+
+// NewDomainCommand to manage domain mappings
+func NewDomainCommand(p *commands.KnParams) *cobra.Command {
+	domainCmd := &cobra.Command{
+		Use:     "domain COMMAND",
+		Short:   "Manage domain mappings",
+		Aliases: []string{"domains"},
+	}
+	domainCmd.AddCommand(NewDomainMappingCreateCommand(p))
+	domainCmd.AddCommand(NewDomainMappingDescribeCommand(p))
+	domainCmd.AddCommand(NewDomainMappingUpdateCommand(p))
+	domainCmd.AddCommand(NewDomainMappingDeleteCommand(p))
+	domainCmd.AddCommand(NewDomainMappingListCommand(p))
+	return domainCmd
+}
+
+type RefFlags struct {
+	reference string
+}
+
+var refMappings = map[string]schema.GroupVersionResource{
+	"ksvc": {
+		Resource: "services",
+		Group:    "serving.knative.dev",
+		Version:  "v1",
+	},
+	"kroute": {
+		Resource: "routes",
+		Group:    "serving.knative.dev",
+		Version:  "v1",
+	},
+}
+
+func (f *RefFlags) Add(cmd *cobra.Command) {
+	cmd.Flags().StringVar(&f.reference, "ref", "", "")
+	cmd.Flag("ref").Usage = "Addressable target reference for Domain Mapping. " +
+		"You can specify a Knative service, a Knative route. " +
+		"Examples: '--ref' ksvc:hello' or simply '--ref hello' for a Knative service 'hello', " +
+		"'--ref' kroute:hello' for a Knative route 'hello'. " +
+		"'--ref ksvc:mysvc:mynamespace' for a Knative service 'mysvc' in another namespace 'mynamespace', " +
+		"If a prefix is not provided, it is considered as a Knative service in the current namespace. " +
+		"If referring to a Knative service in another namespace, 'ksvc:name:namespace' combination must be provided explicitly."
+}
+
+func (f RefFlags) Resolve(ctx context.Context, knclient clientdynamic.KnDynamicClient, namespace string) (*duckv1.KReference, error) {
+	client := knclient.RawClient()
+	if f.reference == "" {
+		return nil, nil
+	}
+
+	prefix, name, refNamespace := parseType(f.reference)
+	gvr, ok := refMappings[prefix]
+	if !ok {
+		return nil, fmt.Errorf("unsupported sink prefix: '%s'", prefix)
+	}
+	if refNamespace != "" {
+		namespace = refNamespace
+	}
+	obj, err := client.Resource(gvr).Namespace(namespace).Get(ctx, name, metav1.GetOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	result := &duckv1.KReference{
+		Kind:       obj.GetKind(),
+		APIVersion: obj.GetAPIVersion(),
+		Name:       obj.GetName(),
+		Namespace:  namespace,
+	}
+	return result, nil
+}
+
+func parseType(ref string) (string, string, string) {
+	parts := strings.SplitN(ref, ":", 3)
+	switch {
+	case len(parts) == 1:
+		return "ksvc", parts[0], ""
+	case len(parts) == 3:
+		return parts[0], parts[1], parts[2]
+	default:
+		return parts[0], parts[1], ""
+	}
+}
diff --git a/pkg/kn/commands/domain/human_readable_flags.go b/pkg/kn/commands/domain/human_readable_flags.go
new file mode 100644
index 00000000..3747043a
--- /dev/null
+++ b/pkg/kn/commands/domain/human_readable_flags.go
@@ -0,0 +1,72 @@
+// Copyright © 2019 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"knative.dev/serving/pkg/apis/serving/v1alpha1"
+
+	"knative.dev/client/pkg/kn/commands"
+	hprinters "knative.dev/client/pkg/printers"
+)
+
+// DomainMappingListHandlers adds print handlers for route list command
+func DomainMappingListHandlers(h hprinters.PrintHandler) {
+	dmColumnDefinitions := []metav1beta1.TableColumnDefinition{
+		{Name: "Namespace", Type: "string", Description: "Namespace of the Knative service", Priority: 0},
+		{Name: "Name", Type: "string", Description: "Name of the Knative domain mapping.", Priority: 1},
+		{Name: "URL", Type: "string", Description: "URL of the Knative domain mapping.", Priority: 1},
+		{Name: "Ready", Type: "string", Description: "Ready condition status of the Knative domain mapping.", Priority: 1},
+		{Name: "Ksvc", Type: "string", Description: "Name of the referenced Knative service", Priority: 1},
+	}
+	h.TableHandler(dmColumnDefinitions, printDomainMapping)
+	h.TableHandler(dmColumnDefinitions, printDomainMappingList)
+}
+
+// printDomainMappingList populates the Knative domain mapping list table rows
+func printDomainMappingList(domainMappingList *v1alpha1.DomainMappingList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	rows := make([]metav1beta1.TableRow, 0, len(domainMappingList.Items))
+	for i := range domainMappingList.Items {
+		dm := &domainMappingList.Items[i]
+		r, err := printDomainMapping(dm, options)
+		if err != nil {
+			return nil, err
+		}
+		rows = append(rows, r...)
+	}
+	return rows, nil
+}
+
+// printDomainMapping populates the Knative domain mapping table rows
+func printDomainMapping(domainMapping *v1alpha1.DomainMapping, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	name := domainMapping.Name
+	url := domainMapping.Status.URL
+	ready := commands.ReadyCondition(domainMapping.Status.Conditions)
+	ksvc := domainMapping.Spec.Ref.Name
+	row := metav1beta1.TableRow{
+		Object: runtime.RawExtension{Object: domainMapping},
+	}
+	if options.AllNamespaces {
+		row.Cells = append(row.Cells, domainMapping.Namespace)
+	}
+
+	row.Cells = append(row.Cells,
+		name,
+		url,
+		ready,
+		ksvc)
+	return []metav1beta1.TableRow{row}, nil
+}
diff --git a/pkg/kn/commands/domain/list.go b/pkg/kn/commands/domain/list.go
new file mode 100644
index 00000000..00934129
--- /dev/null
+++ b/pkg/kn/commands/domain/list.go
@@ -0,0 +1,69 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+)
+
+// NewDomainMappingListCommand represents 'kn revision list' command
+func NewDomainMappingListCommand(p *commands.KnParams) *cobra.Command {
+	listFlags := flags.NewListPrintFlags(DomainMappingListHandlers)
+	cmd := &cobra.Command{
+		Use:     "list",
+		Short:   "List domain mappings",
+		Aliases: []string{"ls"},
+		Example: `
+  # List all domain mappings
+  kn domain list
+
+  # List all domain mappings in JSON output format
+  kn revision list -o json`,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+			if namespace == "" {
+				listFlags.EnsureWithNamespace()
+			}
+
+			client, err := p.NewServingV1alpha1Client(namespace)
+			if err != nil {
+				return err
+			}
+
+			domainMappingList, err := client.ListDomainMappings(cmd.Context())
+			if err != nil {
+				return err
+			}
+
+			if len(domainMappingList.Items) == 0 {
+				fmt.Fprintf(cmd.OutOrStdout(), "No domain mapping found.\n")
+				return nil
+			}
+
+			return listFlags.Print(domainMappingList, cmd.OutOrStdout())
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), true)
+	listFlags.AddFlags(cmd)
+	return cmd
+}
diff --git a/pkg/kn/commands/domain/update.go b/pkg/kn/commands/domain/update.go
new file mode 100644
index 00000000..fd24a263
--- /dev/null
+++ b/pkg/kn/commands/domain/update.go
@@ -0,0 +1,84 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	knerrors "knative.dev/client/pkg/errors"
+	"knative.dev/client/pkg/kn/commands"
+)
+
+// NewDomainMappingUpdateCommand to create event channels
+func NewDomainMappingUpdateCommand(p *commands.KnParams) *cobra.Command {
+	var refFlags RefFlags
+	cmd := &cobra.Command{
+		Use:   "update NAME",
+		Short: "Update a domain mapping",
+		Example: `
+  # Update a domain mappings 'hello.example.com' for Knative service 'hello'
+  kn domain create hello.example.com --refFlags hello`,
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("'kn domain create' requires the domain name given as single argument")
+			}
+			name := args[0]
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			client, err := p.NewServingV1alpha1Client(namespace)
+			if err != nil {
+				return err
+			}
+
+			toUpdate, err := client.GetDomainMapping(cmd.Context(), name)
+			if err != nil {
+				return err
+			}
+
+			if toUpdate.GetDeletionTimestamp() != nil {
+				return fmt.Errorf("can't update domain mapping '%s' because it has been marked for deletion", name)
+			}
+
+			dynamicClient, err := p.NewDynamicClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			reference, err := refFlags.Resolve(cmd.Context(), dynamicClient, namespace)
+			if err != nil {
+				return err
+			}
+			toUpdate.Spec.Ref = *reference
+
+			err = client.UpdateDomainMapping(cmd.Context(), toUpdate)
+			if err != nil {
+				return knerrors.GetError(err)
+			}
+
+			fmt.Fprintf(cmd.OutOrStdout(), "Domain mapping '%s' updated in namespace '%s'.\n", name, namespace)
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	refFlags.Add(cmd)
+	cmd.MarkFlagRequired("refFlags")
+	return cmd
+}
diff --git a/pkg/kn/commands/types.go b/pkg/kn/commands/types.go
index 524c521e..9af0a19c 100644
--- a/pkg/kn/commands/types.go
+++ b/pkg/kn/commands/types.go
@@ -27,6 +27,7 @@ import (
 	messagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1"
 	sourcesv1alpha2client "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2"
 	servingv1client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1"
+	servingv1alpha1client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
 
 	"knative.dev/client/pkg/sources/v1alpha2"
 	"knative.dev/client/pkg/util"
@@ -36,21 +37,23 @@ import (
 	clienteventingv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
 	clientmessagingv1beta1 "knative.dev/client/pkg/messaging/v1beta1"
 	clientservingv1 "knative.dev/client/pkg/serving/v1"
+	clientservingv1alpha1 "knative.dev/client/pkg/serving/v1alpha1"
 )
 
 // KnParams for creating commands. Useful for inserting mocks for testing.
 type KnParams struct {
-	Output                 io.Writer
-	KubeCfgPath            string
-	KubeContext            string
-	KubeCluster            string
-	ClientConfig           clientcmd.ClientConfig
-	NewServingClient       func(namespace string) (clientservingv1.KnServingClient, error)
-	NewGitopsServingClient func(namespace string, dir string) (clientservingv1.KnServingClient, error)
-	NewSourcesClient       func(namespace string) (v1alpha2.KnSourcesClient, error)
-	NewEventingClient      func(namespace string) (clienteventingv1beta1.KnEventingClient, error)
-	NewMessagingClient     func(namespace string) (clientmessagingv1beta1.KnMessagingClient, error)
-	NewDynamicClient       func(namespace string) (clientdynamic.KnDynamicClient, error)
+	Output                   io.Writer
+	KubeCfgPath              string
+	KubeContext              string
+	KubeCluster              string
+	ClientConfig             clientcmd.ClientConfig
+	NewServingClient         func(namespace string) (clientservingv1.KnServingClient, error)
+	NewServingV1alpha1Client func(namespace string) (clientservingv1alpha1.KnServingClient, error)
+	NewGitopsServingClient   func(namespace string, dir string) (clientservingv1.KnServingClient, error)
+	NewSourcesClient         func(namespace string) (v1alpha2.KnSourcesClient, error)
+	NewEventingClient        func(namespace string) (clienteventingv1beta1.KnEventingClient, error)
+	NewMessagingClient       func(namespace string) (clientmessagingv1beta1.KnMessagingClient, error)
+	NewDynamicClient         func(namespace string) (clientdynamic.KnDynamicClient, error)
 
 	// General global options
 	LogHTTP bool
@@ -64,6 +67,10 @@ func (params *KnParams) Initialize() {
 		params.NewServingClient = params.newServingClient
 	}
 
+	if params.NewServingV1alpha1Client == nil {
+		params.NewServingV1alpha1Client = params.newServingClientV1alpha1
+	}
+
 	if params.NewGitopsServingClient == nil {
 		params.NewGitopsServingClient = params.newGitopsServingClient
 	}
@@ -98,6 +105,19 @@ func (params *KnParams) newServingClient(namespace string) (clientservingv1.KnSe
 	return clientservingv1.NewKnServingClient(client, namespace), nil
 }
 
+func (params *KnParams) newServingClientV1alpha1(namespace string) (clientservingv1alpha1.KnServingClient, error) {
+	restConfig, err := params.RestConfig()
+	if err != nil {
+		return nil, err
+	}
+
+	client, err := servingv1alpha1client.NewForConfig(restConfig)
+	if err != nil {
+		return nil, err
+	}
+	return clientservingv1alpha1.NewKnServingClient(client, namespace), nil
+}
+
 func (params *KnParams) newGitopsServingClient(namespace string, dir string) (clientservingv1.KnServingClient, error) {
 	return clientservingv1.NewKnServingGitOpsClient(namespace, dir), nil
 }
diff --git a/pkg/kn/root/root.go b/pkg/kn/root/root.go
index 4d8a59f6..65780c43 100644
--- a/pkg/kn/root/root.go
+++ b/pkg/kn/root/root.go
@@ -20,6 +20,8 @@ import (
 	"strings"
 	"text/template"
 
+	"knative.dev/client/pkg/kn/commands/domain"
+
 	"github.com/spf13/cobra"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
@@ -88,6 +90,7 @@ func NewRootCommand(helpFuncs *template.FuncMap) (*cobra.Command, error) {
 				service.NewServiceCommand(p),
 				revision.NewRevisionCommand(p),
 				route.NewRouteCommand(p),
+				domain.NewDomainCommand(p),
 			},
 		},
 		{
diff --git a/pkg/serving/v1alpha1/client.go b/pkg/serving/v1alpha1/client.go
new file mode 100644
index 00000000..262e9b05
--- /dev/null
+++ b/pkg/serving/v1alpha1/client.go
@@ -0,0 +1,166 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1alpha1
+
+import (
+	"context"
+
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	knerrors "knative.dev/client/pkg/errors"
+	"knative.dev/client/pkg/util"
+	servingv1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+	"knative.dev/serving/pkg/client/clientset/versioned/scheme"
+	clientv1alpha1 "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
+)
+
+// KnServingClient to work with Serving v1alpha1 resources
+type KnServingClient interface {
+	// Namespace in which this client is operating for
+	Namespace() string
+
+	// GetDomainMapping
+	GetDomainMapping(ctx context.Context, name string) (*servingv1alpha1.DomainMapping, error)
+
+	// CreateDomainMapping
+	CreateDomainMapping(ctx context.Context, domainMapping *servingv1alpha1.DomainMapping) error
+
+	// UpdateDomainMapping
+	UpdateDomainMapping(ctx context.Context, domainMapping *servingv1alpha1.DomainMapping) error
+
+	// DeleteDomainMapping
+	DeleteDomainMapping(ctx context.Context, name string) error
+
+	// ListDomainMappings
+	ListDomainMappings(ctx context.Context) (*servingv1alpha1.DomainMappingList, error)
+}
+
+type knServingClient struct {
+	client    clientv1alpha1.ServingV1alpha1Interface
+	namespace string
+}
+
+// NewKnServingClient create a new client facade for the provided namespace
+func NewKnServingClient(client clientv1alpha1.ServingV1alpha1Interface, namespace string) KnServingClient {
+	return &knServingClient{
+		client:    client,
+		namespace: namespace,
+	}
+}
+
+// Namespace in which this client is operating for
+func (cl *knServingClient) Namespace() string {
+	return cl.namespace
+}
+
+// GetDomainMapping gets DomainMapping by name
+func (cl *knServingClient) GetDomainMapping(ctx context.Context, name string) (*servingv1alpha1.DomainMapping, error) {
+	dm, err := cl.client.DomainMappings(cl.namespace).Get(ctx, name, v1.GetOptions{})
+	if err != nil {
+		return nil, knerrors.GetError(err)
+	}
+	err = updateServingGvk(dm)
+	if err != nil {
+		return nil, err
+	}
+	return dm, nil
+}
+
+// CreateDomainMapping creates provided DomainMapping
+func (cl *knServingClient) CreateDomainMapping(ctx context.Context, domainMapping *servingv1alpha1.DomainMapping) error {
+	_, err := cl.client.DomainMappings(cl.namespace).Create(ctx, domainMapping, v1.CreateOptions{})
+	if err != nil {
+		return knerrors.GetError(err)
+	}
+	return updateServingGvk(domainMapping)
+}
+
+// UpdateDomainMapping updates provided DomainMapping
+func (cl *knServingClient) UpdateDomainMapping(ctx context.Context, domainMapping *servingv1alpha1.DomainMapping) error {
+	_, err := cl.client.DomainMappings(cl.namespace).Update(ctx, domainMapping, v1.UpdateOptions{})
+	if err != nil {
+		return knerrors.GetError(err)
+	}
+	return updateServingGvk(domainMapping)
+}
+
+// DeleteDomainMapping deletes DomainMapping by name
+func (cl *knServingClient) DeleteDomainMapping(ctx context.Context, name string) error {
+	err := cl.client.DomainMappings(cl.namespace).Delete(ctx, name, v1.DeleteOptions{})
+	if err != nil {
+		return knerrors.GetError(err)
+	}
+	return nil
+}
+
+// ListDomainMappings lists all DomainMappings
+func (cl *knServingClient) ListDomainMappings(ctx context.Context) (*servingv1alpha1.DomainMappingList, error) {
+	domainMappingList, err := cl.client.DomainMappings(cl.namespace).List(ctx, v1.ListOptions{})
+	if err != nil {
+		return nil, knerrors.GetError(err)
+	}
+	dmListNew := domainMappingList.DeepCopy()
+	err = updateServingGvk(dmListNew)
+	if err != nil {
+		return nil, err
+	}
+	dmListNew.Items = make([]servingv1alpha1.DomainMapping, len(domainMappingList.Items))
+	for idx, domainMapping := range domainMappingList.Items {
+		domainMappingClone := domainMapping.DeepCopy()
+		err := updateServingGvk(domainMappingClone)
+		if err != nil {
+			return nil, err
+		}
+		dmListNew.Items[idx] = *domainMappingClone
+	}
+	return dmListNew, nil
+}
+
+func updateServingGvk(obj runtime.Object) error {
+	return util.UpdateGroupVersionKindWithScheme(obj, servingv1alpha1.SchemeGroupVersion, scheme.Scheme)
+}
+
+// DomainMappingBuilder is for building the domainMapping
+type DomainMappingBuilder struct {
+	domainMapping *servingv1alpha1.DomainMapping
+}
+
+// NewDomainMappingBuilder for building domainMapping object
+func NewDomainMappingBuilder(name string) *DomainMappingBuilder {
+	return &DomainMappingBuilder{domainMapping: &servingv1alpha1.DomainMapping{
+		ObjectMeta: v1.ObjectMeta{
+			Name: name,
+		},
+	}}
+}
+
+// Namespace for domainMapping builder
+func (b *DomainMappingBuilder) Namespace(ns string) *DomainMappingBuilder {
+	b.domainMapping.Namespace = ns
+	return b
+}
+
+// Reference for domainMapping builder
+func (b *DomainMappingBuilder) Reference(reference duckv1.KReference) *DomainMappingBuilder {
+	b.domainMapping.Spec.Ref = reference
+	return b
+}
+
+// Build to return an instance of domainMapping object
+func (b *DomainMappingBuilder) Build() *servingv1alpha1.DomainMapping {
+	return b.domainMapping
+}
diff --git a/pkg/serving/v1alpha1/client_mock.go b/pkg/serving/v1alpha1/client_mock.go
new file mode 100644
index 00000000..036e3d1c
--- /dev/null
+++ b/pkg/serving/v1alpha1/client_mock.go
@@ -0,0 +1,116 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1alpha1
+
+import (
+	"context"
+	"testing"
+
+	"knative.dev/client/pkg/util/mock"
+	servingv1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+)
+
+// MockKnServingClient client mock
+type MockKnServingClient struct {
+	t        *testing.T
+	recorder *ServingRecorder
+}
+
+// NewMockKnServiceClient returns a new mock instance which you need to record for
+func NewMockKnServiceClient(t *testing.T, ns ...string) *MockKnServingClient {
+	namespace := "default"
+	if len(ns) > 0 {
+		namespace = ns[0]
+	}
+	return &MockKnServingClient{
+		t:        t,
+		recorder: &ServingRecorder{mock.NewRecorder(t, namespace)},
+	}
+}
+
+// ServingRecorder recorder for service
+type ServingRecorder struct {
+	r *mock.Recorder
+}
+
+// Recorder returns the record instance
+func (c *MockKnServingClient) Recorder() *ServingRecorder {
+	return c.recorder
+}
+
+// Validate checks that every recorded method has been called
+func (sr *ServingRecorder) Validate() {
+	sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
+}
+
+// Namespace of this client
+func (c *MockKnServingClient) Namespace() string {
+	return c.recorder.r.Namespace()
+}
+
+// GetDomainMapping mock function recorder
+func (sr *ServingRecorder) GetDomainMapping(name interface{}, domainMapping *servingv1alpha1.DomainMapping, err error) {
+	sr.r.Add("GetDomainMapping", []interface{}{name}, []interface{}{domainMapping, err})
+}
+
+// GetDomainMapping mock function
+func (c *MockKnServingClient) GetDomainMapping(ctx context.Context, name string) (*servingv1alpha1.DomainMapping, error) {
+	call := c.recorder.r.VerifyCall("GetDomainMapping", name)
+	return call.Result[0].(*servingv1alpha1.DomainMapping), mock.ErrorOrNil(call.Result[1])
+}
+
+// CreateDomainMapping recorder function
+func (sr *ServingRecorder) CreateDomainMapping(domainMapping interface{}, err error) {
+	sr.r.Add("CreateDomainMapping", []interface{}{domainMapping}, []interface{}{err})
+}
+
+// CreateDomainMapping mock function
+func (c *MockKnServingClient) CreateDomainMapping(ctx context.Context, domainMapping *servingv1alpha1.DomainMapping) error {
+	call := c.recorder.r.VerifyCall("CreateDomainMapping", domainMapping)
+	return mock.ErrorOrNil(call.Result[0])
+}
+
+// UpdateDomainMapping recorder function
+func (sr *ServingRecorder) UpdateDomainMapping(domainMapping interface{}, err error) {
+	sr.r.Add("UpdateDomainMapping", []interface{}{domainMapping}, []interface{}{err})
+}
+
+// UpdateDomainMapping mock function
+func (c *MockKnServingClient) UpdateDomainMapping(ctx context.Context, domainMapping *servingv1alpha1.DomainMapping) error {
+	call := c.recorder.r.VerifyCall("UpdateDomainMapping", domainMapping)
+	return mock.ErrorOrNil(call.Result[0])
+}
+
+// DeleteDomainMapping recorder function
+func (sr *ServingRecorder) DeleteDomainMapping(name string, err error) {
+	sr.r.Add("DeleteDomainMapping", []interface{}{name}, []interface{}{err})
+}
+
+// DeleteDomainMapping mock function
+func (c *MockKnServingClient) DeleteDomainMapping(ctx context.Context, name string) error {
+	call := c.recorder.r.VerifyCall("DeleteDomainMapping", name)
+	return mock.ErrorOrNil(call.Result[0])
+}
+
+// ListDomainMappings recorder function
+func (sr *ServingRecorder) ListDomainMappings(domainMappingList *servingv1alpha1.DomainMappingList, err error) {
+	sr.r.Add("ListDomainMappings", nil, []interface{}{domainMappingList, err})
+}
+
+// ListDomainMappings mock function
+func (c *MockKnServingClient) ListDomainMappings(ctx context.Context) (*servingv1alpha1.DomainMappingList, error) {
+	call := c.recorder.r.VerifyCall("ListDomainMappings")
+	return call.Result[0].(*servingv1alpha1.DomainMappingList), mock.ErrorOrNil(call.Result[1])
+}
diff --git a/third_party/VENDOR-LICENSE/golang.org/x/xerrors/LICENSE b/third_party/VENDOR-LICENSE/golang.org/x/xerrors/LICENSE
deleted file mode 100644
index e4a47e17..00000000
--- a/third_party/VENDOR-LICENSE/golang.org/x/xerrors/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2019 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-   * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-   * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-   * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
index 51ce36fb..e4ffca83 100644
--- a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
+++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
@@ -11,7 +11,6 @@ import (
 	"time"
 
 	"github.com/google/go-cmp/cmp"
-	"golang.org/x/xerrors"
 )
 
 func equateAlways(_, _ interface{}) bool { return true }
@@ -147,10 +146,3 @@ func areConcreteErrors(x, y interface{}) bool {
 	_, ok2 := y.(error)
 	return ok1 && ok2
 }
-
-func compareErrors(x, y interface{}) bool {
-	xe := x.(error)
-	ye := y.(error)
-	// TODO(≥go1.13): Use standard definition of errors.Is.
-	return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
-}
diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go
new file mode 100644
index 00000000..26fe25d6
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go
@@ -0,0 +1,15 @@
+// Copyright 2021, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.13
+
+package cmpopts
+
+import "errors"
+
+func compareErrors(x, y interface{}) bool {
+	xe := x.(error)
+	ye := y.(error)
+	return errors.Is(xe, ye) || errors.Is(ye, xe)
+}
diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go
new file mode 100644
index 00000000..6eeb8d6e
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go
@@ -0,0 +1,18 @@
+// Copyright 2021, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.13
+
+// TODO(≥go1.13): For support on <go1.13, we use the xerrors package.
+// Drop this file when we no longer support older Go versions.
+
+package cmpopts
+
+import "golang.org/x/xerrors"
+
+func compareErrors(x, y interface{}) bool {
+	xe := x.(error)
+	ye := y.(error)
+	return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
+}
diff --git a/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go
index a6c070cf..104bb305 100644
--- a/vendor/github.com/google/go-cmp/cmp/report_compare.go
+++ b/vendor/github.com/google/go-cmp/cmp/report_compare.go
@@ -79,7 +79,7 @@ func (opts formatOptions) verbosity() uint {
 	}
 }
 
-const maxVerbosityPreset = 3
+const maxVerbosityPreset = 6
 
 // verbosityPreset modifies the verbosity settings given an index
 // between 0 and maxVerbosityPreset, inclusive.
@@ -100,7 +100,7 @@ func verbosityPreset(opts formatOptions, i int) formatOptions {
 func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) {
 	if opts.DiffMode == diffIdentical {
 		opts = opts.WithVerbosity(1)
-	} else {
+	} else if opts.verbosity() < 3 {
 		opts = opts.WithVerbosity(3)
 	}
 
diff --git a/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go
index da04caf1..168f92f3 100644
--- a/vendor/github.com/google/go-cmp/cmp/report_slices.go
+++ b/vendor/github.com/google/go-cmp/cmp/report_slices.go
@@ -26,8 +26,6 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
 		return false // No differences detected
 	case !v.ValueX.IsValid() || !v.ValueY.IsValid():
 		return false // Both values must be valid
-	case v.Type.Kind() == reflect.Slice && (v.ValueX.Len() == 0 || v.ValueY.Len() == 0):
-		return false // Both slice values have to be non-empty
 	case v.NumIgnored > 0:
 		return false // Some ignore option was used
 	case v.NumTransformed > 0:
@@ -45,7 +43,16 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
 		return false
 	}
 
-	switch t := v.Type; t.Kind() {
+	// Check whether this is an interface with the same concrete types.
+	t := v.Type
+	vx, vy := v.ValueX, v.ValueY
+	if t.Kind() == reflect.Interface && !vx.IsNil() && !vy.IsNil() && vx.Elem().Type() == vy.Elem().Type() {
+		vx, vy = vx.Elem(), vy.Elem()
+		t = vx.Type()
+	}
+
+	// Check whether we provide specialized diffing for this type.
+	switch t.Kind() {
 	case reflect.String:
 	case reflect.Array, reflect.Slice:
 		// Only slices of primitive types have specialized handling.
@@ -57,6 +64,11 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
 			return false
 		}
 
+		// Both slice values have to be non-empty.
+		if t.Kind() == reflect.Slice && (vx.Len() == 0 || vy.Len() == 0) {
+			return false
+		}
+
 		// If a sufficient number of elements already differ,
 		// use specialized formatting even if length requirement is not met.
 		if v.NumDiff > v.NumSame {
@@ -68,7 +80,7 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
 
 	// Use specialized string diffing for longer slices or strings.
 	const minLength = 64
-	return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength
+	return vx.Len() >= minLength && vy.Len() >= minLength
 }
 
 // FormatDiffSlice prints a diff for the slices (or strings) represented by v.
@@ -77,6 +89,11 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
 func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
 	assert(opts.DiffMode == diffUnknown)
 	t, vx, vy := v.Type, v.ValueX, v.ValueY
+	if t.Kind() == reflect.Interface {
+		vx, vy = vx.Elem(), vy.Elem()
+		t = vx.Type()
+		opts = opts.WithTypeMode(emitType)
+	}
 
 	// Auto-detect the type of the data.
 	var isLinedText, isText, isBinary bool
diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go
index c40e6403..e684ebd1 100644
--- a/vendor/github.com/prometheus/common/model/time.go
+++ b/vendor/github.com/prometheus/common/model/time.go
@@ -14,6 +14,7 @@
 package model
 
 import (
+	"encoding/json"
 	"fmt"
 	"math"
 	"regexp"
@@ -254,6 +255,37 @@ func (d Duration) String() string {
 	return r
 }
 
+// MarshalJSON implements the json.Marshaler interface.
+func (d Duration) MarshalJSON() ([]byte, error) {
+	return json.Marshal(d.String())
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (d *Duration) UnmarshalJSON(bytes []byte) error {
+	var s string
+	if err := json.Unmarshal(bytes, &s); err != nil {
+		return err
+	}
+	dur, err := ParseDuration(s)
+	if err != nil {
+		return err
+	}
+	*d = dur
+	return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (d *Duration) MarshalText() ([]byte, error) {
+	return []byte(d.String()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (d *Duration) UnmarshalText(text []byte) error {
+	var err error
+	*d, err = ParseDuration(string(text))
+	return err
+}
+
 // MarshalYAML implements the yaml.Marshaler interface.
 func (d Duration) MarshalYAML() (interface{}, error) {
 	return d.String(), nil
diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go
index 41e7274a..d56b77cc 100644
--- a/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go
+++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go
@@ -11,6 +11,7 @@ import (
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
 // LoadBalancerClient is the client API for LoadBalancer service.
diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go
index 75bbf87d..efdbd13f 100644
--- a/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go
+++ b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go
@@ -11,6 +11,7 @@ import (
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
 // HandshakerServiceClient is the client API for HandshakerService service.
diff --git a/vendor/google.golang.org/grpc/encoding/proto/proto.go b/vendor/google.golang.org/grpc/encoding/proto/proto.go
index e1230fdd..3009b35a 100644
--- a/vendor/google.golang.org/grpc/encoding/proto/proto.go
+++ b/vendor/google.golang.org/grpc/encoding/proto/proto.go
@@ -21,6 +21,8 @@
 package proto
 
 import (
+	"fmt"
+
 	"github.com/golang/protobuf/proto"
 	"google.golang.org/grpc/encoding"
 )
@@ -36,11 +38,19 @@ func init() {
 type codec struct{}
 
 func (codec) Marshal(v interface{}) ([]byte, error) {
-	return proto.Marshal(v.(proto.Message))
+	vv, ok := v.(proto.Message)
+	if !ok {
+		return nil, fmt.Errorf("failed to marshal, message is %T, want proto.Message", v)
+	}
+	return proto.Marshal(vv)
 }
 
 func (codec) Unmarshal(data []byte, v interface{}) error {
-	return proto.Unmarshal(data, v.(proto.Message))
+	vv, ok := v.(proto.Message)
+	if !ok {
+		return fmt.Errorf("failed to unmarshal, message is %T, want proto.Message", v)
+	}
+	return proto.Unmarshal(data, vv)
 }
 
 func (codec) Name() string {
diff --git a/vendor/google.golang.org/grpc/regenerate.sh b/vendor/google.golang.org/grpc/regenerate.sh
index ed52187d..fc6725b8 100644
--- a/vendor/google.golang.org/grpc/regenerate.sh
+++ b/vendor/google.golang.org/grpc/regenerate.sh
@@ -40,6 +40,9 @@ echo "go install cmd/protoc-gen-go-grpc"
 echo "git clone https://github.com/grpc/grpc-proto"
 git clone --quiet https://github.com/grpc/grpc-proto ${WORKDIR}/grpc-proto
 
+echo "git clone https://github.com/protocolbuffers/protobuf"
+git clone --quiet https://github.com/protocolbuffers/protobuf ${WORKDIR}/protobuf
+
 # Pull in code.proto as a proto dependency
 mkdir -p ${WORKDIR}/googleapis/google/rpc
 echo "curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/rpc/code.proto"
@@ -87,6 +90,7 @@ for src in ${SOURCES[@]}; do
     -I"." \
     -I${WORKDIR}/grpc-proto \
     -I${WORKDIR}/googleapis \
+    -I${WORKDIR}/protobuf/src \
     -I${WORKDIR}/istio \
     ${src}
 done
@@ -97,6 +101,7 @@ for src in ${LEGACY_SOURCES[@]}; do
     -I"." \
     -I${WORKDIR}/grpc-proto \
     -I${WORKDIR}/googleapis \
+    -I${WORKDIR}/protobuf/src \
     -I${WORKDIR}/istio \
     ${src}
 done
diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go
index ea5bb8d0..c0a1208f 100644
--- a/vendor/google.golang.org/grpc/rpc_util.go
+++ b/vendor/google.golang.org/grpc/rpc_util.go
@@ -888,8 +888,7 @@ type channelzData struct {
 // buffer files to ensure compatibility with the gRPC version used.  The latest
 // support package version is 7.
 //
-// Older versions are kept for compatibility. They may be removed if
-// compatibility cannot be maintained.
+// Older versions are kept for compatibility.
 //
 // These constants should not be referenced from any other code.
 const (
diff --git a/vendor/google.golang.org/grpc/status/status.go b/vendor/google.golang.org/grpc/status/status.go
index 01e182c3..54d18718 100644
--- a/vendor/google.golang.org/grpc/status/status.go
+++ b/vendor/google.golang.org/grpc/status/status.go
@@ -73,9 +73,11 @@ func FromProto(s *spb.Status) *Status {
 	return status.FromProto(s)
 }
 
-// FromError returns a Status representing err if it was produced from this
-// package or has a method `GRPCStatus() *Status`. Otherwise, ok is false and a
-// Status is returned with codes.Unknown and the original error message.
+// FromError returns a Status representing err if it was produced by this
+// package or has a method `GRPCStatus() *Status`.
+// If err is nil, a Status is returned with codes.OK and no message.
+// Otherwise, ok is false and a Status is returned with codes.Unknown and
+// the original error message.
 func FromError(err error) (s *Status, ok bool) {
 	if err == nil {
 		return nil, true
diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go
index 685b91c7..51024d6b 100644
--- a/vendor/google.golang.org/grpc/version.go
+++ b/vendor/google.golang.org/grpc/version.go
@@ -19,4 +19,4 @@
 package grpc
 
 // Version is the current grpc version.
-const Version = "1.35.0"
+const Version = "1.36.0"
diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go
index 7e27a9cb..f40e8029 100644
--- a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go
+++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go
@@ -117,6 +117,7 @@ type TriggerStatus struct {
 	duckv1.Status `json:",inline"`
 
 	// SubscriberURI is the resolved URI of the receiver for this Trigger.
+	// +optional
 	SubscriberURI *apis.URL `json:"subscriberUri,omitempty"`
 }
 
diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/trigger_types.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/trigger_types.go
index 49b5d04b..3a5c9ccf 100644
--- a/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/trigger_types.go
+++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/trigger_types.go
@@ -120,6 +120,7 @@ type TriggerStatus struct {
 	duckv1.Status `json:",inline"`
 
 	// SubscriberURI is the resolved URI of the receiver for this Trigger.
+	// +optional
 	SubscriberURI *apis.URL `json:"subscriberUri,omitempty"`
 }
 
diff --git a/vendor/knative.dev/eventing/pkg/apis/messaging/v1/subscription_defaults.go b/vendor/knative.dev/eventing/pkg/apis/messaging/v1/subscription_defaults.go
index c2ddc46a..6cdf2bab 100644
--- a/vendor/knative.dev/eventing/pkg/apis/messaging/v1/subscription_defaults.go
+++ b/vendor/knative.dev/eventing/pkg/apis/messaging/v1/subscription_defaults.go
@@ -25,5 +25,9 @@ func (s *Subscription) SetDefaults(ctx context.Context) {
 }
 
 func (ss *SubscriptionSpec) SetDefaults(ctx context.Context) {
-	// TODO anything?
+	// HACK if a channel ref is a kafka channel ref, we need to hack it around to use only v1beta1
+	//  TODO(slinkydeveloper) REMOVE AFTER 0.22 release
+	if ss.Channel.Kind == "KafkaChannel" && ss.Channel.APIVersion == "messaging.knative.dev/v1alpha1" {
+		ss.Channel.APIVersion = "messaging.knative.dev/v1beta1"
+	}
 }
diff --git a/vendor/knative.dev/eventing/pkg/apis/messaging/v1/subscription_validation.go b/vendor/knative.dev/eventing/pkg/apis/messaging/v1/subscription_validation.go
index f2496bc7..e3f3a517 100644
--- a/vendor/knative.dev/eventing/pkg/apis/messaging/v1/subscription_validation.go
+++ b/vendor/knative.dev/eventing/pkg/apis/messaging/v1/subscription_validation.go
@@ -80,8 +80,16 @@ func (s *Subscription) CheckImmutableFields(ctx context.Context, original *Subsc
 		return nil
 	}
 
+	// TODO(slinkydeveloper)
+	//  HACK around the immutability check to make sure the update script can upgrade the api version
+	//  REMOVE AFTER 0.22 release
+	ignoredFields := []string{"Subscriber", "Reply"}
+	if original.Spec.Channel.Kind == "KafkaChannel" && original.Spec.Channel.APIVersion == "messaging.knative.dev/v1alpha1" && s.Spec.Channel.APIVersion == "messaging.knative.dev/v1beta1" {
+		ignoredFields = append(ignoredFields, "Channel.APIVersion")
+	}
+
 	// Only Subscriber and Reply are mutable.
-	ignoreArguments := cmpopts.IgnoreFields(SubscriptionSpec{}, "Subscriber", "Reply")
+	ignoreArguments := cmpopts.IgnoreFields(SubscriptionSpec{}, ignoredFields...)
 	if diff, err := kmp.ShortDiff(original.Spec, s.Spec, ignoreArguments); err != nil {
 		return &apis.FieldError{
 			Message: "Failed to diff Subscription",
diff --git a/vendor/knative.dev/eventing/pkg/apis/messaging/v1beta1/subscription_defaults.go b/vendor/knative.dev/eventing/pkg/apis/messaging/v1beta1/subscription_defaults.go
index 16fd42ea..6694bb17 100644
--- a/vendor/knative.dev/eventing/pkg/apis/messaging/v1beta1/subscription_defaults.go
+++ b/vendor/knative.dev/eventing/pkg/apis/messaging/v1beta1/subscription_defaults.go
@@ -25,5 +25,9 @@ func (s *Subscription) SetDefaults(ctx context.Context) {
 }
 
 func (ss *SubscriptionSpec) SetDefaults(ctx context.Context) {
-	// TODO anything?
+	// HACK if a channel ref is a kafka channel ref, we need to hack it around to use only v1beta1
+	//  TODO(slinkydeveloper) REMOVE AFTER 0.22 release
+	if ss.Channel.Kind == "KafkaChannel" && ss.Channel.APIVersion == "messaging.knative.dev/v1alpha1" {
+		ss.Channel.APIVersion = "messaging.knative.dev/v1beta1"
+	}
 }
diff --git a/vendor/knative.dev/eventing/pkg/apis/messaging/v1beta1/subscription_validation.go b/vendor/knative.dev/eventing/pkg/apis/messaging/v1beta1/subscription_validation.go
index 5cf8c2e8..6d316efb 100644
--- a/vendor/knative.dev/eventing/pkg/apis/messaging/v1beta1/subscription_validation.go
+++ b/vendor/knative.dev/eventing/pkg/apis/messaging/v1beta1/subscription_validation.go
@@ -75,8 +75,16 @@ func (s *Subscription) CheckImmutableFields(ctx context.Context, original *Subsc
 		return nil
 	}
 
+	// TODO(slinkydeveloper)
+	//  HACK around the immutability check to make sure the update script can upgrade the api version
+	//  REMOVE AFTER 0.22 release
+	ignoredFields := []string{"Subscriber", "Reply"}
+	if original.Spec.Channel.Kind == "KafkaChannel" && original.Spec.Channel.APIVersion == "messaging.knative.dev/v1alpha1" && s.Spec.Channel.APIVersion == "messaging.knative.dev/v1beta1" {
+		ignoredFields = append(ignoredFields, "Channel.APIVersion")
+	}
+
 	// Only Subscriber and Reply are mutable.
-	ignoreArguments := cmpopts.IgnoreFields(SubscriptionSpec{}, "Subscriber", "Reply")
+	ignoreArguments := cmpopts.IgnoreFields(SubscriptionSpec{}, ignoredFields...)
 	if diff, err := kmp.ShortDiff(original.Spec, s.Spec, ignoreArguments); err != nil {
 		return &apis.FieldError{
 			Message: "Failed to diff Subscription",
diff --git a/vendor/knative.dev/hack/library.sh b/vendor/knative.dev/hack/library.sh
index f8f8b629..de744c1d 100644
--- a/vendor/knative.dev/hack/library.sh
+++ b/vendor/knative.dev/hack/library.sh
@@ -156,6 +156,9 @@ function wait_until_object_does_not_exist() {
 }
 
 # Waits until all pods are running in the given namespace.
+# This function handles some edge cases that `kubectl wait` does not support,
+# and it provides nice debug info on the state of the pod if it failed,
+# that’s why we have this long bash function instead of using `kubectl wait`.
 # Parameters: $1 - namespace.
 function wait_until_pods_running() {
   echo -n "Waiting until all pods in namespace $1 are up"
@@ -163,7 +166,7 @@ function wait_until_pods_running() {
   for i in {1..150}; do  # timeout after 5 minutes
     # List all pods. Ignore Terminating pods as those have either been replaced through
     # a deployment or terminated on purpose (through chaosduck for example).
-    local pods="$(kubectl get pods --no-headers -n $1 2>/dev/null | grep -v Terminating)"
+    local pods="$(kubectl get pods --no-headers -n $1 | grep -v Terminating)"
     # All pods must be running (ignore ImagePull error to allow the pod to retry)
     local not_running_pods=$(echo "${pods}" | grep -v Running | grep -v Completed | grep -v ErrImagePull | grep -v ImagePullBackOff)
     if [[ -n "${pods}" ]] && [[ -z "${not_running_pods}" ]]; then
diff --git a/vendor/knative.dev/networking/pkg/network.go b/vendor/knative.dev/networking/pkg/network.go
index 40914e06..0342b0fe 100644
--- a/vendor/knative.dev/networking/pkg/network.go
+++ b/vendor/knative.dev/networking/pkg/network.go
@@ -180,6 +180,9 @@ const (
 	// load balancers to not load balance the respective request but to
 	// send it to the request's target directly.
 	PassthroughLoadbalancingHeaderName = "K-Passthrough-Lb"
+
+	// EnableMeshPodAddressabilityKey is the config for enabling pod addressability in mesh.
+	EnableMeshPodAddressabilityKey = "enable-mesh-pod-addressability"
 )
 
 // DomainTemplateValues are the available properties people can choose from
@@ -251,6 +254,14 @@ type Config struct {
 	// cluster administrator is responsible for pre-creating ClusterDomainClaims
 	// and delegating them to namespaces via their spec.Namespace field.
 	AutocreateClusterDomainClaims bool
+
+	// EnableMeshPodAddressability specifies whether networking plugins will add
+	// additional information to deployed applications to make their pods directl
+	// accessible via their IPs even if mesh is enabled and thus direct-addressability
+	// is usually not possible.
+	// Consumers like Knative Serving can use this setting to adjust their behavior
+	// accordingly, i.e. to drop fallback solutions for non-pod-addressable systems.
+	EnableMeshPodAddressability bool
 }
 
 // HTTPProtocol indicates a type of HTTP endpoint behavior
@@ -298,6 +309,7 @@ func NewConfigFromMap(data map[string]string) (*Config, error) {
 		cm.AsString(TagTemplateKey, &nc.TagTemplate),
 		cm.AsInt(RolloutDurationKey, &nc.RolloutDurationSecs),
 		cm.AsBool(AutocreateClusterDomainClaimsKey, &nc.AutocreateClusterDomainClaims),
+		cm.AsBool(EnableMeshPodAddressabilityKey, &nc.EnableMeshPodAddressability),
 	); err != nil {
 		return nil, err
 	}
diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go
index 78ff9673..9471b5db 100644
--- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go
+++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go
@@ -204,7 +204,7 @@ const (
 // NewImpl returns a {{.controllerImpl|raw}} that handles queuing and feeding work from
 // the queue through an implementation of {{.controllerReconciler|raw}}, delegating to
 // the provided Interface and optional Finalizer methods. OptionsFn is used to return
-// {{.controllerOptions|raw}} to be used but the internal reconciler.
+// {{.controllerOptions|raw}} to be used by the internal reconciler.
 func NewImpl(ctx {{.contextContext|raw}}, r Interface{{if .hasClass}}, classValue string{{end}}, optionsFns ...{{.controllerOptionsFn|raw}}) *{{.controllerImpl|raw}} {
 	logger := {{.loggingFromContext|raw}}(ctx)
 
diff --git a/vendor/knative.dev/pkg/leaderelection/config.go b/vendor/knative.dev/pkg/leaderelection/config.go
index 96164bd0..3d9df1dc 100644
--- a/vendor/knative.dev/pkg/leaderelection/config.go
+++ b/vendor/knative.dev/pkg/leaderelection/config.go
@@ -134,8 +134,8 @@ type statefulSetID struct {
 
 func (ssID *statefulSetID) Decode(v string) error {
 	if i := strings.LastIndex(v, "-"); i != -1 {
-		ui, err := strconv.ParseUint(v[i+1:], 10, 64)
-		ssID.ordinal = int(ui)
+		ui, err := strconv.Atoi(v[i+1:])
+		ssID.ordinal = ui
 		ssID.ssName = v[:i]
 		return err
 	}
diff --git a/vendor/knative.dev/serving/pkg/apis/autoscaling/annotation_validation.go b/vendor/knative.dev/serving/pkg/apis/autoscaling/annotation_validation.go
index 805047e2..3fdf2bb6 100644
--- a/vendor/knative.dev/serving/pkg/apis/autoscaling/annotation_validation.go
+++ b/vendor/knative.dev/serving/pkg/apis/autoscaling/annotation_validation.go
@@ -52,7 +52,7 @@ func getIntGE0(m map[string]string, k string) (int32, *apis.FieldError) {
 // ValidateAnnotations verifies the autoscaling annotations.
 func ValidateAnnotations(ctx context.Context, config *autoscalerconfig.Config, anns map[string]string) *apis.FieldError {
 	return validateClass(anns).
-		Also(validateMinMaxScale(ctx, config, anns)).
+		Also(validateMinMaxScale(config, anns)).
 		Also(validateFloats(anns)).
 		Also(validateWindow(anns)).
 		Also(validateLastPodRetention(anns)).
@@ -173,7 +173,7 @@ func validateWindow(annotations map[string]string) *apis.FieldError {
 	return nil
 }
 
-func validateMinMaxScale(ctx context.Context, config *autoscalerconfig.Config, annotations map[string]string) *apis.FieldError {
+func validateMinMaxScale(config *autoscalerconfig.Config, annotations map[string]string) *apis.FieldError {
 	min, errs := getIntGE0(annotations, MinScaleAnnotationKey)
 	max, err := getIntGE0(annotations, MaxScaleAnnotationKey)
 	errs = errs.Also(err)
@@ -184,21 +184,30 @@ func validateMinMaxScale(ctx context.Context, config *autoscalerconfig.Config, a
 			Paths:   []string{MaxScaleAnnotationKey, MinScaleAnnotationKey},
 		})
 	}
-	_, exists := annotations[MaxScaleAnnotationKey]
-	// If max scale annotation is not set but default MaxScale is set, then max scale will not be unlimited.
-	if !apis.IsInCreate(ctx) || config.MaxScaleLimit == 0 || (!exists && config.MaxScale > 0) {
-		return errs
+
+	if _, hasMaxScaleAnnotation := annotations[MaxScaleAnnotationKey]; hasMaxScaleAnnotation {
+		errs = errs.Also(validateMaxScaleWithinLimit(max, config.MaxScaleLimit))
+	}
+
+	return errs
+}
+
+func validateMaxScaleWithinLimit(maxScale, maxScaleLimit int32) (errs *apis.FieldError) {
+	if maxScaleLimit == 0 {
+		return nil
 	}
-	if max > config.MaxScaleLimit {
-		errs = errs.Also(apis.ErrOutOfBoundsValue(
-			max, 1, config.MaxScaleLimit, MaxScaleAnnotationKey))
+
+	if maxScale > maxScaleLimit {
+		errs = errs.Also(apis.ErrOutOfBoundsValue(maxScale, 1, maxScaleLimit, MaxScaleAnnotationKey))
 	}
-	if max == 0 {
+
+	if maxScale == 0 {
 		errs = errs.Also(&apis.FieldError{
-			Message: fmt.Sprint("maxScale=0 (unlimited), must be less than ", config.MaxScaleLimit),
+			Message: fmt.Sprint("maxScale=0 (unlimited), must be less than ", maxScaleLimit),
 			Paths:   []string{MaxScaleAnnotationKey},
 		})
 	}
+
 	return errs
 }
 
diff --git a/vendor/knative.dev/serving/pkg/apis/serving/v1/revision_lifecycle.go b/vendor/knative.dev/serving/pkg/apis/serving/v1/revision_lifecycle.go
index 8335d5f5..bc71421e 100644
--- a/vendor/knative.dev/serving/pkg/apis/serving/v1/revision_lifecycle.go
+++ b/vendor/knative.dev/serving/pkg/apis/serving/v1/revision_lifecycle.go
@@ -24,7 +24,7 @@ import (
 	"k8s.io/apimachinery/pkg/runtime/schema"
 
 	"knative.dev/pkg/apis"
-	av1alpha1 "knative.dev/serving/pkg/apis/autoscaling/v1alpha1"
+	autoscalingv1alpha1 "knative.dev/serving/pkg/apis/autoscaling/v1alpha1"
 	"knative.dev/serving/pkg/apis/config"
 	"knative.dev/serving/pkg/apis/serving"
 )
@@ -168,9 +168,9 @@ func (rs *RevisionStatus) PropagateDeploymentStatus(original *appsv1.DeploymentS
 }
 
 // PropagateAutoscalerStatus propagates autoscaler's status to the revision's status.
-func (rs *RevisionStatus) PropagateAutoscalerStatus(ps *av1alpha1.PodAutoscalerStatus) {
+func (rs *RevisionStatus) PropagateAutoscalerStatus(ps *autoscalingv1alpha1.PodAutoscalerStatus) {
 	// Reflect the PA status in our own.
-	cond := ps.GetCondition(av1alpha1.PodAutoscalerConditionReady)
+	cond := ps.GetCondition(autoscalingv1alpha1.PodAutoscalerConditionReady)
 	if cond == nil {
 		rs.MarkActiveUnknown("Deploying", "")
 		return
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/doc.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/doc.go
new file mode 100644
index 00000000..41e872fe
--- /dev/null
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated typed clients.
+package v1alpha1
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/domainmapping.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/domainmapping.go
new file mode 100644
index 00000000..606935b6
--- /dev/null
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/domainmapping.go
@@ -0,0 +1,195 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+	"context"
+	"time"
+
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	types "k8s.io/apimachinery/pkg/types"
+	watch "k8s.io/apimachinery/pkg/watch"
+	rest "k8s.io/client-go/rest"
+	v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+	scheme "knative.dev/serving/pkg/client/clientset/versioned/scheme"
+)
+
+// DomainMappingsGetter has a method to return a DomainMappingInterface.
+// A group's client should implement this interface.
+type DomainMappingsGetter interface {
+	DomainMappings(namespace string) DomainMappingInterface
+}
+
+// DomainMappingInterface has methods to work with DomainMapping resources.
+type DomainMappingInterface interface {
+	Create(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.CreateOptions) (*v1alpha1.DomainMapping, error)
+	Update(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.UpdateOptions) (*v1alpha1.DomainMapping, error)
+	UpdateStatus(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.UpdateOptions) (*v1alpha1.DomainMapping, error)
+	Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
+	DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
+	Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.DomainMapping, error)
+	List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.DomainMappingList, error)
+	Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
+	Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.DomainMapping, err error)
+	DomainMappingExpansion
+}
+
+// domainMappings implements DomainMappingInterface
+type domainMappings struct {
+	client rest.Interface
+	ns     string
+}
+
+// newDomainMappings returns a DomainMappings
+func newDomainMappings(c *ServingV1alpha1Client, namespace string) *domainMappings {
+	return &domainMappings{
+		client: c.RESTClient(),
+		ns:     namespace,
+	}
+}
+
+// Get takes name of the domainMapping, and returns the corresponding domainMapping object, and an error if there is any.
+func (c *domainMappings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.DomainMapping, err error) {
+	result = &v1alpha1.DomainMapping{}
+	err = c.client.Get().
+		Namespace(c.ns).
+		Resource("domainmappings").
+		Name(name).
+		VersionedParams(&options, scheme.ParameterCodec).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// List takes label and field selectors, and returns the list of DomainMappings that match those selectors.
+func (c *domainMappings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.DomainMappingList, err error) {
+	var timeout time.Duration
+	if opts.TimeoutSeconds != nil {
+		timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+	}
+	result = &v1alpha1.DomainMappingList{}
+	err = c.client.Get().
+		Namespace(c.ns).
+		Resource("domainmappings").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Timeout(timeout).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// Watch returns a watch.Interface that watches the requested domainMappings.
+func (c *domainMappings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
+	var timeout time.Duration
+	if opts.TimeoutSeconds != nil {
+		timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+	}
+	opts.Watch = true
+	return c.client.Get().
+		Namespace(c.ns).
+		Resource("domainmappings").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Timeout(timeout).
+		Watch(ctx)
+}
+
+// Create takes the representation of a domainMapping and creates it.  Returns the server's representation of the domainMapping, and an error, if there is any.
+func (c *domainMappings) Create(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.CreateOptions) (result *v1alpha1.DomainMapping, err error) {
+	result = &v1alpha1.DomainMapping{}
+	err = c.client.Post().
+		Namespace(c.ns).
+		Resource("domainmappings").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(domainMapping).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// Update takes the representation of a domainMapping and updates it. Returns the server's representation of the domainMapping, and an error, if there is any.
+func (c *domainMappings) Update(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.UpdateOptions) (result *v1alpha1.DomainMapping, err error) {
+	result = &v1alpha1.DomainMapping{}
+	err = c.client.Put().
+		Namespace(c.ns).
+		Resource("domainmappings").
+		Name(domainMapping.Name).
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(domainMapping).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+func (c *domainMappings) UpdateStatus(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.UpdateOptions) (result *v1alpha1.DomainMapping, err error) {
+	result = &v1alpha1.DomainMapping{}
+	err = c.client.Put().
+		Namespace(c.ns).
+		Resource("domainmappings").
+		Name(domainMapping.Name).
+		SubResource("status").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(domainMapping).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// Delete takes name of the domainMapping and deletes it. Returns an error if one occurs.
+func (c *domainMappings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
+	return c.client.Delete().
+		Namespace(c.ns).
+		Resource("domainmappings").
+		Name(name).
+		Body(&opts).
+		Do(ctx).
+		Error()
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *domainMappings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
+	var timeout time.Duration
+	if listOpts.TimeoutSeconds != nil {
+		timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
+	}
+	return c.client.Delete().
+		Namespace(c.ns).
+		Resource("domainmappings").
+		VersionedParams(&listOpts, scheme.ParameterCodec).
+		Timeout(timeout).
+		Body(&opts).
+		Do(ctx).
+		Error()
+}
+
+// Patch applies the patch and returns the patched domainMapping.
+func (c *domainMappings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.DomainMapping, err error) {
+	result = &v1alpha1.DomainMapping{}
+	err = c.client.Patch(pt).
+		Namespace(c.ns).
+		Resource("domainmappings").
+		Name(name).
+		SubResource(subresources...).
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(data).
+		Do(ctx).
+		Into(result)
+	return
+}
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/doc.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/doc.go
new file mode 100644
index 00000000..c7f6e65c
--- /dev/null
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// Package fake has the automatically generated clients.
+package fake
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_domainmapping.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_domainmapping.go
new file mode 100644
index 00000000..f224fe83
--- /dev/null
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_domainmapping.go
@@ -0,0 +1,142 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+	"context"
+
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	labels "k8s.io/apimachinery/pkg/labels"
+	schema "k8s.io/apimachinery/pkg/runtime/schema"
+	types "k8s.io/apimachinery/pkg/types"
+	watch "k8s.io/apimachinery/pkg/watch"
+	testing "k8s.io/client-go/testing"
+	v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+)
+
+// FakeDomainMappings implements DomainMappingInterface
+type FakeDomainMappings struct {
+	Fake *FakeServingV1alpha1
+	ns   string
+}
+
+var domainmappingsResource = schema.GroupVersionResource{Group: "serving.knative.dev", Version: "v1alpha1", Resource: "domainmappings"}
+
+var domainmappingsKind = schema.GroupVersionKind{Group: "serving.knative.dev", Version: "v1alpha1", Kind: "DomainMapping"}
+
+// Get takes name of the domainMapping, and returns the corresponding domainMapping object, and an error if there is any.
+func (c *FakeDomainMappings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.DomainMapping, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewGetAction(domainmappingsResource, c.ns, name), &v1alpha1.DomainMapping{})
+
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.DomainMapping), err
+}
+
+// List takes label and field selectors, and returns the list of DomainMappings that match those selectors.
+func (c *FakeDomainMappings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.DomainMappingList, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewListAction(domainmappingsResource, domainmappingsKind, c.ns, opts), &v1alpha1.DomainMappingList{})
+
+	if obj == nil {
+		return nil, err
+	}
+
+	label, _, _ := testing.ExtractFromListOptions(opts)
+	if label == nil {
+		label = labels.Everything()
+	}
+	list := &v1alpha1.DomainMappingList{ListMeta: obj.(*v1alpha1.DomainMappingList).ListMeta}
+	for _, item := range obj.(*v1alpha1.DomainMappingList).Items {
+		if label.Matches(labels.Set(item.Labels)) {
+			list.Items = append(list.Items, item)
+		}
+	}
+	return list, err
+}
+
+// Watch returns a watch.Interface that watches the requested domainMappings.
+func (c *FakeDomainMappings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
+	return c.Fake.
+		InvokesWatch(testing.NewWatchAction(domainmappingsResource, c.ns, opts))
+
+}
+
+// Create takes the representation of a domainMapping and creates it.  Returns the server's representation of the domainMapping, and an error, if there is any.
+func (c *FakeDomainMappings) Create(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.CreateOptions) (result *v1alpha1.DomainMapping, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewCreateAction(domainmappingsResource, c.ns, domainMapping), &v1alpha1.DomainMapping{})
+
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.DomainMapping), err
+}
+
+// Update takes the representation of a domainMapping and updates it. Returns the server's representation of the domainMapping, and an error, if there is any.
+func (c *FakeDomainMappings) Update(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.UpdateOptions) (result *v1alpha1.DomainMapping, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewUpdateAction(domainmappingsResource, c.ns, domainMapping), &v1alpha1.DomainMapping{})
+
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.DomainMapping), err
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+func (c *FakeDomainMappings) UpdateStatus(ctx context.Context, domainMapping *v1alpha1.DomainMapping, opts v1.UpdateOptions) (*v1alpha1.DomainMapping, error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewUpdateSubresourceAction(domainmappingsResource, "status", c.ns, domainMapping), &v1alpha1.DomainMapping{})
+
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.DomainMapping), err
+}
+
+// Delete takes name of the domainMapping and deletes it. Returns an error if one occurs.
+func (c *FakeDomainMappings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
+	_, err := c.Fake.
+		Invokes(testing.NewDeleteAction(domainmappingsResource, c.ns, name), &v1alpha1.DomainMapping{})
+
+	return err
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *FakeDomainMappings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
+	action := testing.NewDeleteCollectionAction(domainmappingsResource, c.ns, listOpts)
+
+	_, err := c.Fake.Invokes(action, &v1alpha1.DomainMappingList{})
+	return err
+}
+
+// Patch applies the patch and returns the patched domainMapping.
+func (c *FakeDomainMappings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.DomainMapping, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewPatchSubresourceAction(domainmappingsResource, c.ns, name, pt, data, subresources...), &v1alpha1.DomainMapping{})
+
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.DomainMapping), err
+}
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_serving_client.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_serving_client.go
new file mode 100644
index 00000000..3dde006e
--- /dev/null
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake/fake_serving_client.go
@@ -0,0 +1,40 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+	rest "k8s.io/client-go/rest"
+	testing "k8s.io/client-go/testing"
+	v1alpha1 "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
+)
+
+type FakeServingV1alpha1 struct {
+	*testing.Fake
+}
+
+func (c *FakeServingV1alpha1) DomainMappings(namespace string) v1alpha1.DomainMappingInterface {
+	return &FakeDomainMappings{c, namespace}
+}
+
+// RESTClient returns a RESTClient that is used to communicate
+// with API server by this client implementation.
+func (c *FakeServingV1alpha1) RESTClient() rest.Interface {
+	var ret *rest.RESTClient
+	return ret
+}
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/generated_expansion.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/generated_expansion.go
new file mode 100644
index 00000000..ce84dcec
--- /dev/null
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/generated_expansion.go
@@ -0,0 +1,21 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+type DomainMappingExpansion interface{}
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/serving_client.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/serving_client.go
new file mode 100644
index 00000000..1a4aa0ff
--- /dev/null
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/serving_client.go
@@ -0,0 +1,89 @@
+/*
+Copyright 2020 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+	rest "k8s.io/client-go/rest"
+	v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+	"knative.dev/serving/pkg/client/clientset/versioned/scheme"
+)
+
+type ServingV1alpha1Interface interface {
+	RESTClient() rest.Interface
+	DomainMappingsGetter
+}
+
+// ServingV1alpha1Client is used to interact with features provided by the serving.knative.dev group.
+type ServingV1alpha1Client struct {
+	restClient rest.Interface
+}
+
+func (c *ServingV1alpha1Client) DomainMappings(namespace string) DomainMappingInterface {
+	return newDomainMappings(c, namespace)
+}
+
+// NewForConfig creates a new ServingV1alpha1Client for the given config.
+func NewForConfig(c *rest.Config) (*ServingV1alpha1Client, error) {
+	config := *c
+	if err := setConfigDefaults(&config); err != nil {
+		return nil, err
+	}
+	client, err := rest.RESTClientFor(&config)
+	if err != nil {
+		return nil, err
+	}
+	return &ServingV1alpha1Client{client}, nil
+}
+
+// NewForConfigOrDie creates a new ServingV1alpha1Client for the given config and
+// panics if there is an error in the config.
+func NewForConfigOrDie(c *rest.Config) *ServingV1alpha1Client {
+	client, err := NewForConfig(c)
+	if err != nil {
+		panic(err)
+	}
+	return client
+}
+
+// New creates a new ServingV1alpha1Client for the given RESTClient.
+func New(c rest.Interface) *ServingV1alpha1Client {
+	return &ServingV1alpha1Client{c}
+}
+
+func setConfigDefaults(config *rest.Config) error {
+	gv := v1alpha1.SchemeGroupVersion
+	config.GroupVersion = &gv
+	config.APIPath = "/apis"
+	config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
+
+	if config.UserAgent == "" {
+		config.UserAgent = rest.DefaultKubernetesUserAgent()
+	}
+
+	return nil
+}
+
+// RESTClient returns a RESTClient that is used to communicate
+// with API server by this client implementation.
+func (c *ServingV1alpha1Client) RESTClient() rest.Interface {
+	if c == nil {
+		return nil
+	}
+	return c.restClient
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 5f3d7ce3..864f7282 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -132,7 +132,7 @@ github.com/golang/protobuf/ptypes/timestamp
 github.com/golang/protobuf/ptypes/wrappers
 # github.com/google/btree v1.0.0
 github.com/google/btree
-# github.com/google/go-cmp v0.5.4
+# github.com/google/go-cmp v0.5.5
 ## explicit
 github.com/google/go-cmp/cmp
 github.com/google/go-cmp/cmp/cmpopts
@@ -223,7 +223,7 @@ github.com/prometheus/client_golang/prometheus/internal
 github.com/prometheus/client_golang/prometheus/promhttp
 # github.com/prometheus/client_model v0.2.0
 github.com/prometheus/client_model/go
-# github.com/prometheus/common v0.15.0
+# github.com/prometheus/common v0.19.0
 github.com/prometheus/common/expfmt
 github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
 github.com/prometheus/common/log
@@ -270,7 +270,7 @@ github.com/spf13/pflag
 github.com/spf13/viper
 # github.com/subosito/gotenv v1.2.0
 github.com/subosito/gotenv
-# go.opencensus.io v0.22.6
+# go.opencensus.io v0.23.0
 go.opencensus.io
 go.opencensus.io/internal
 go.opencensus.io/internal/tagencoding
@@ -404,7 +404,7 @@ google.golang.org/genproto/googleapis/monitoring/v3
 google.golang.org/genproto/googleapis/rpc/status
 google.golang.org/genproto/googleapis/type/calendarperiod
 google.golang.org/genproto/protobuf/field_mask
-# google.golang.org/grpc v1.35.0
+# google.golang.org/grpc v1.36.0
 google.golang.org/grpc
 google.golang.org/grpc/attributes
 google.golang.org/grpc/backoff
@@ -771,7 +771,7 @@ k8s.io/kube-openapi/pkg/util/sets
 k8s.io/utils/buffer
 k8s.io/utils/integer
 k8s.io/utils/trace
-# knative.dev/eventing v0.21.1-0.20210312002228-3b427377abe0
+# knative.dev/eventing v0.21.1-0.20210331231822-8f35d42544e0
 ## explicit
 knative.dev/eventing/pkg/apis/config
 knative.dev/eventing/pkg/apis/duck
@@ -800,15 +800,15 @@ knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1/fake
 knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1
 knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2
 knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake
-# knative.dev/hack v0.0.0-20210309141825-9b73a256fd9a
+# knative.dev/hack v0.0.0-20210325223819-b6ab329907d3
 ## explicit
 knative.dev/hack
-# knative.dev/networking v0.0.0-20210311190926-430a689490e6
+# knative.dev/networking v0.0.0-20210331064822-999a7708876c
 ## explicit
 knative.dev/networking/pkg
 knative.dev/networking/pkg/apis/networking
 knative.dev/networking/pkg/apis/networking/v1alpha1
-# knative.dev/pkg v0.0.0-20210311174826-40488532be3f
+# knative.dev/pkg v0.0.0-20210331065221-952fdd90dbb0
 ## explicit
 knative.dev/pkg/apis
 knative.dev/pkg/apis/duck
@@ -852,7 +852,7 @@ knative.dev/pkg/tracing/config
 knative.dev/pkg/tracing/propagation
 knative.dev/pkg/tracing/propagation/tracecontextb3
 knative.dev/pkg/tracker
-# knative.dev/serving v0.21.1-0.20210311225828-1583394c61cb
+# knative.dev/serving v0.21.1-0.20210401115722-fc58a32f0ef6
 ## explicit
 knative.dev/serving/pkg/apis/autoscaling
 knative.dev/serving/pkg/apis/autoscaling/v1alpha1
@@ -865,6 +865,8 @@ knative.dev/serving/pkg/autoscaler/config/autoscalerconfig
 knative.dev/serving/pkg/client/clientset/versioned/scheme
 knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1
 knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/fake
+knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1
+knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake
 knative.dev/serving/pkg/gc
 knative.dev/serving/pkg/networking
 knative.dev/serving/pkg/reconciler/route/config


Test patch:
diff --git a/pkg/kn/commands/domain/create_test.go b/pkg/kn/commands/domain/create_test.go
new file mode 100644
index 00000000..95e13dc0
--- /dev/null
+++ b/pkg/kn/commands/domain/create_test.go
@@ -0,0 +1,60 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"testing"
+
+	"gotest.tools/v3/assert"
+
+	dynamicfake "knative.dev/client/pkg/dynamic/fake"
+	"knative.dev/client/pkg/serving/v1alpha1"
+	"knative.dev/client/pkg/util"
+)
+
+func TestDomainMappingCreate(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient(client.Namespace(), createService("foo"))
+
+	servingRecorder := client.Recorder()
+	servingRecorder.CreateDomainMapping(createDomainMapping("foo.bar", createServiceRef("foo", "default")), nil)
+
+	out, err := executeDomainCommand(client, dynamicClient, "create", "foo.bar", "--ref", "foo")
+	assert.NilError(t, err, "Domain mapping should be created")
+	assert.Assert(t, util.ContainsAll(out, "Domain", "mapping", "foo.bar", "created", "namespace", "default"))
+
+	servingRecorder.Validate()
+}
+func TestDomainMappingCreateWithError(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient(client.Namespace(), createService("foo"))
+
+	// No call should be recorded
+	servingRecorder := client.Recorder()
+
+	_, err := executeDomainCommand(client, dynamicClient, "create", "--ref", "foo")
+	assert.ErrorContains(t, err, "domain create")
+	assert.Assert(t, util.ContainsAll(err.Error(), "domain create", "requires", "name", "argument"))
+
+	_, err = executeDomainCommand(client, dynamicClient, "create", "bar")
+	assert.ErrorContains(t, err, "required flag")
+	assert.Assert(t, util.ContainsAll(err.Error(), "required", "flag", "not", "set"))
+
+	_, err = executeDomainCommand(client, dynamicClient, "create", "foo.bar", "--ref", "bar")
+	assert.ErrorContains(t, err, "not found")
+	assert.Assert(t, util.ContainsAll(err.Error(), "services", "\"bar\"", "not", "found"))
+
+	servingRecorder.Validate()
+}
diff --git a/pkg/kn/commands/domain/delete_test.go b/pkg/kn/commands/domain/delete_test.go
new file mode 100644
index 00000000..2e7418fc
--- /dev/null
+++ b/pkg/kn/commands/domain/delete_test.go
@@ -0,0 +1,66 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"errors"
+	"testing"
+
+	"gotest.tools/v3/assert"
+
+	dynamicfake "knative.dev/client/pkg/dynamic/fake"
+	"knative.dev/client/pkg/serving/v1alpha1"
+	"knative.dev/client/pkg/util"
+)
+
+func TestDomainMappingDelete(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	servingRecorder := client.Recorder()
+	servingRecorder.DeleteDomainMapping("foo.bar", nil)
+
+	out, err := executeDomainCommand(client, nil, "delete", "foo.bar")
+	assert.NilError(t, err, "Domain mapping should be deleted")
+	assert.Assert(t, util.ContainsAll(out, "Domain", "mapping", "foo.bar", "deleted", "namespace", "default"))
+
+	servingRecorder.Validate()
+}
+
+func TestDomainMappingDeleteNotFound(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	servingRecorder := client.Recorder()
+	servingRecorder.DeleteDomainMapping("foo.bar", errors.New("domainmappings.serving.knative.dev \"foo.bar\" not found"))
+
+	_, err := executeDomainCommand(client, nil, "delete", "foo.bar")
+	assert.ErrorContains(t, err, "not found")
+	assert.Assert(t, util.ContainsAll(err.Error(), "domainmappings.serving.knative.dev", "\"foo.bar\"", "not", "found"))
+
+	servingRecorder.Validate()
+}
+
+func TestDomainMappingDeleteWithError(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient(client.Namespace(), createService("foo"))
+
+	// No call should be recorded
+	servingRecorder := client.Recorder()
+
+	_, err := executeDomainCommand(client, dynamicClient, "delete")
+	assert.ErrorContains(t, err, "domain delete")
+	assert.Assert(t, util.ContainsAll(err.Error(), "domain delete", "requires", "name", "argument"))
+
+	servingRecorder.Validate()
+}
diff --git a/pkg/kn/commands/domain/describe_test.go b/pkg/kn/commands/domain/describe_test.go
new file mode 100644
index 00000000..6bce321a
--- /dev/null
+++ b/pkg/kn/commands/domain/describe_test.go
@@ -0,0 +1,115 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"errors"
+	"strings"
+	"testing"
+
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"gotest.tools/v3/assert"
+	"gotest.tools/v3/assert/cmp"
+
+	"knative.dev/client/pkg/serving/v1alpha1"
+	"knative.dev/client/pkg/util"
+	"knative.dev/pkg/apis"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+	servingv1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+)
+
+func TestDomainMappingDescribe(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	servingRecorder := client.Recorder()
+	servingRecorder.GetDomainMapping("foo.bar", getDomainMapping(), nil)
+
+	out, err := executeDomainCommand(client, nil, "describe", "foo.bar")
+	assert.NilError(t, err)
+	assert.Assert(t, cmp.Regexp("Name:\\s+foo.bar", out))
+	assert.Assert(t, cmp.Regexp("Namespace:\\s+default", out))
+	assert.Assert(t, util.ContainsAll(out, "URL:", "http://foo.bar"))
+	assert.Assert(t, util.ContainsAll(out, "Conditions:", "Ready"))
+
+	// There're 2 empty lines used in the "describe" formatting
+	lineCounter := 0
+	for _, line := range strings.Split(strings.TrimSpace(out), "\n") {
+		if line == "" {
+			lineCounter++
+		}
+	}
+	assert.Equal(t, lineCounter, 2)
+
+	servingRecorder.Validate()
+}
+
+func TestDomainMappingDescribeError(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	servingRecorder := client.Recorder()
+	servingRecorder.GetDomainMapping("foo.bar", getDomainMapping(), errors.New("domainmappings.serving.knative.dev 'foo.bar' not found"))
+
+	_, err := executeDomainCommand(client, nil, "describe", "foo.bar")
+	assert.ErrorContains(t, err, "foo", "not found")
+
+	servingRecorder.Validate()
+}
+
+func TestDomainMappingDescribeURL(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	servingRecorder := client.Recorder()
+	servingRecorder.GetDomainMapping("foo.bar", getDomainMapping(), nil)
+
+	out, err := executeDomainCommand(client, nil, "describe", "foo.bar", "-o", "url")
+	assert.NilError(t, err)
+	assert.Assert(t, util.ContainsAll(out, "http://foo.bar"))
+
+	servingRecorder.Validate()
+}
+
+func TestDomainMappingDescribeYAML(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	servingRecorder := client.Recorder()
+	servingRecorder.GetDomainMapping("foo.bar", getDomainMapping(), nil)
+
+	out, err := executeDomainCommand(client, nil, "describe", "foo.bar", "-o", "yaml")
+	assert.NilError(t, err)
+	assert.Assert(t, util.ContainsAll(out, "kind: DomainMapping", "spec:", "status:", "metadata:"))
+
+	servingRecorder.Validate()
+}
+
+func getDomainMapping() *servingv1alpha1.DomainMapping {
+	dm := createDomainMapping("foo.bar", createServiceRef("foo", "default"))
+	dm.TypeMeta = v1.TypeMeta{
+		Kind:       "DomainMapping",
+		APIVersion: "serving.knative.dev/v1alpha1",
+	}
+	dm.Status = servingv1alpha1.DomainMappingStatus{
+		Status: duckv1.Status{
+			Conditions: duckv1.Conditions{
+				apis.Condition{
+					Type:   "Ready",
+					Status: "True",
+				},
+			},
+		},
+		URL: &apis.URL{Scheme: "http", Host: "foo.bar"},
+	}
+	return dm
+}
diff --git a/pkg/kn/commands/domain/domain_test.go b/pkg/kn/commands/domain/domain_test.go
new file mode 100644
index 00000000..a72f844e
--- /dev/null
+++ b/pkg/kn/commands/domain/domain_test.go
@@ -0,0 +1,191 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"bytes"
+	"context"
+	"testing"
+
+	"gotest.tools/v3/assert"
+
+	"github.com/spf13/cobra"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/tools/clientcmd"
+
+	kndynamic "knative.dev/client/pkg/dynamic"
+	dynamicfake "knative.dev/client/pkg/dynamic/fake"
+	"knative.dev/client/pkg/kn/commands"
+	knflags "knative.dev/client/pkg/kn/flags"
+	clientservingv1alpha1 "knative.dev/client/pkg/serving/v1alpha1"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
+	servingv1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+)
+
+// Helper methods
+var blankConfig clientcmd.ClientConfig
+
+const kubeConfig = `kind: Config
+version: v1
+users:
+- name: u
+clusters:
+- name: c
+  cluster:
+    server: example.com
+contexts:
+- name: x
+  context:
+    user: u
+    cluster: c
+current-context: x`
+
+func init() {
+	var err error
+	blankConfig, err = clientcmd.NewClientConfigFromBytes([]byte(kubeConfig))
+	if err != nil {
+		panic(err)
+	}
+}
+
+func TestDomainCommand(t *testing.T) {
+	knParams := &commands.KnParams{}
+	domainCmd := NewDomainCommand(knParams)
+	assert.Equal(t, domainCmd.Name(), "domain")
+	assert.Equal(t, domainCmd.Use, "domain COMMAND")
+	subCommands := make([]string, 0, len(domainCmd.Commands()))
+	for _, cmd := range domainCmd.Commands() {
+		subCommands = append(subCommands, cmd.Name())
+	}
+	expectedSubCommands := []string{"create", "delete", "describe", "list", "update"}
+	assert.DeepEqual(t, subCommands, expectedSubCommands)
+}
+
+type resolveCase struct {
+	ref         string
+	destination *duckv1.KReference
+	errContents string
+}
+
+func TestResolve(t *testing.T) {
+	myksvc := &servingv1.Service{
+		TypeMeta:   metav1.TypeMeta{Kind: "Service", APIVersion: "serving.knative.dev/v1"},
+		ObjectMeta: metav1.ObjectMeta{Name: "myksvc", Namespace: "default"},
+	}
+	mykroute := &servingv1.Route{
+		TypeMeta:   metav1.TypeMeta{Kind: "Route", APIVersion: "serving.knative.dev/v1"},
+		ObjectMeta: metav1.ObjectMeta{Name: "mykroute", Namespace: "default"},
+	}
+	myksvcInOther := &servingv1.Service{
+		TypeMeta:   metav1.TypeMeta{Kind: "Service", APIVersion: "serving.knative.dev/v1"},
+		ObjectMeta: metav1.ObjectMeta{Name: "myksvc", Namespace: "other"},
+	}
+	mykrouteInOther := &servingv1.Route{
+		TypeMeta:   metav1.TypeMeta{Kind: "Route", APIVersion: "serving.knative.dev/v1"},
+		ObjectMeta: metav1.ObjectMeta{Name: "mykroute", Namespace: "other"},
+	}
+
+	cases := []resolveCase{
+		// Test 'name' is considered as Knative service
+		{"myksvc", &duckv1.KReference{Kind: "Service",
+			APIVersion: "serving.knative.dev/v1",
+			Namespace:  "default",
+			Name:       "myksvc"}, ""},
+		// Test 'type:name' format
+		{"ksvc:myksvc", &duckv1.KReference{Kind: "Service",
+			APIVersion: "serving.knative.dev/v1",
+			Namespace:  "default",
+			Name:       "myksvc"}, ""},
+		{"kroute:mykroute", &duckv1.KReference{Kind: "Route",
+			APIVersion: "serving.knative.dev/v1",
+			Namespace:  "default",
+			Name:       "mykroute"}, ""},
+		// Test 'type:name:namespace' format
+		{"ksvc:myksvc:other", &duckv1.KReference{Kind: "Service",
+			APIVersion: "serving.knative.dev/v1",
+			Namespace:  "other",
+			Name:       "myksvc"}, ""},
+		{"kroute:mykroute:other", &duckv1.KReference{Kind: "Route",
+			APIVersion: "serving.knative.dev/v1",
+			Namespace:  "other",
+			Name:       "mykroute"}, ""},
+
+		{"k8ssvc:foo", nil, "unsupported sink prefix: 'k8ssvc'"},
+		{"svc:foo", nil, "unsupported sink prefix: 'svc'"},
+		{"service:foo", nil, "unsupported sink prefix: 'service'"},
+	}
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default", myksvc, mykroute, myksvcInOther, mykrouteInOther)
+	for _, c := range cases {
+		i := &RefFlags{c.ref}
+		result, err := i.Resolve(context.Background(), dynamicClient, "default")
+		if c.destination != nil {
+			assert.DeepEqual(t, result, c.destination)
+			assert.NilError(t, err)
+		} else {
+			assert.ErrorContains(t, err, c.errContents)
+		}
+	}
+}
+
+func TestRefFlagAdd(t *testing.T) {
+	c := &cobra.Command{Use: "reftest"}
+	refFlag := new(RefFlags)
+	refFlag.Add(c)
+	assert.Equal(t, "ref", c.Flag("ref").Name)
+}
+
+func executeDomainCommand(client clientservingv1alpha1.KnServingClient, dynamicClient kndynamic.KnDynamicClient, args ...string) (string, error) {
+	knParams := &commands.KnParams{}
+	knParams.ClientConfig = blankConfig
+
+	output := new(bytes.Buffer)
+	knParams.Output = output
+	knParams.NewServingV1alpha1Client = func(namespace string) (clientservingv1alpha1.KnServingClient, error) {
+		return client, nil
+	}
+	knParams.NewDynamicClient = func(namespace string) (kndynamic.KnDynamicClient, error) {
+		return dynamicClient, nil
+	}
+
+	cmd := NewDomainCommand(knParams)
+	cmd.SetArgs(args)
+	cmd.SetOut(output)
+
+	cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
+		return knflags.ReconcileBoolFlags(cmd.Flags())
+	}
+	err := cmd.Execute()
+	return output.String(), err
+}
+
+func createService(name string) *servingv1.Service {
+	return &servingv1.Service{
+		ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "default"},
+	}
+}
+
+func createDomainMapping(name string, ref duckv1.KReference) *servingv1alpha1.DomainMapping {
+	return clientservingv1alpha1.NewDomainMappingBuilder(name).Namespace("default").Reference(ref).Build()
+}
+
+func createServiceRef(service, namespace string) duckv1.KReference {
+	return duckv1.KReference{Name: service,
+		Kind:       "Service",
+		APIVersion: "serving.knative.dev/v1",
+		Namespace:  namespace,
+	}
+}
diff --git a/pkg/kn/commands/domain/list_test.go b/pkg/kn/commands/domain/list_test.go
new file mode 100644
index 00000000..574b693b
--- /dev/null
+++ b/pkg/kn/commands/domain/list_test.go
@@ -0,0 +1,58 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"strings"
+	"testing"
+
+	"gotest.tools/v3/assert"
+
+	"knative.dev/client/pkg/serving/v1alpha1"
+	"knative.dev/client/pkg/util"
+	servingv1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+)
+
+func TestDomainMappingList(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	dm1 := createDomainMapping("foo1", createServiceRef("foo1", "default"))
+	dm2 := createDomainMapping("foo2", createServiceRef("foo2", "default"))
+	servingRecorder := client.Recorder()
+	servingRecorder.ListDomainMappings(&servingv1alpha1.DomainMappingList{Items: []servingv1alpha1.DomainMapping{*dm1, *dm2}}, nil)
+
+	out, err := executeDomainCommand(client, nil, "list")
+	assert.NilError(t, err, "Domain mapping should be listed")
+
+	outputLines := strings.Split(out, "\n")
+	assert.Check(t, util.ContainsAll(outputLines[0], "NAME", "URL", "READY", "KSVC"))
+	assert.Check(t, util.ContainsAll(outputLines[1], "foo1"))
+	assert.Check(t, util.ContainsAll(outputLines[2], "foo2"))
+
+	servingRecorder.Validate()
+}
+
+func TestDomainMappingListEmpty(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	servingRecorder := client.Recorder()
+	servingRecorder.ListDomainMappings(&servingv1alpha1.DomainMappingList{}, nil)
+
+	out, err := executeDomainCommand(client, nil, "list")
+	assert.NilError(t, err)
+	assert.Assert(t, util.ContainsAll(out, "No", "domain", "mapping", "found"))
+
+	servingRecorder.Validate()
+}
diff --git a/pkg/kn/commands/domain/update_test.go b/pkg/kn/commands/domain/update_test.go
new file mode 100644
index 00000000..f54749a3
--- /dev/null
+++ b/pkg/kn/commands/domain/update_test.go
@@ -0,0 +1,73 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package domain
+
+import (
+	"errors"
+	"testing"
+	"time"
+
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"gotest.tools/v3/assert"
+
+	dynamicfake "knative.dev/client/pkg/dynamic/fake"
+	"knative.dev/client/pkg/serving/v1alpha1"
+	"knative.dev/client/pkg/util"
+)
+
+func TestDomainMappingUpdate(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient(client.Namespace(), createService("foo"), createService("bar"))
+
+	servingRecorder := client.Recorder()
+	servingRecorder.GetDomainMapping("foo.bar", createDomainMapping("foo.bar", createServiceRef("foo", "default")), nil)
+	servingRecorder.UpdateDomainMapping(createDomainMapping("foo.bar", createServiceRef("bar", "default")), nil)
+
+	out, err := executeDomainCommand(client, dynamicClient, "update", "foo.bar", "--ref", "bar")
+	assert.NilError(t, err, "Domain mapping should be updated")
+	assert.Assert(t, util.ContainsAll(out, "Domain", "mapping", "foo.bar", "updated", "namespace", "default"))
+
+	servingRecorder.Validate()
+}
+
+func TestDomainMappingUpdateNotFound(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	servingRecorder := client.Recorder()
+	servingRecorder.GetDomainMapping("foo.bar", nil, errors.New("domainmappings.serving.knative.dev \"foo.bar\" not found"))
+
+	_, err := executeDomainCommand(client, nil, "update", "foo.bar", "--ref", "bar")
+	assert.ErrorContains(t, err, "not found")
+	assert.Assert(t, util.ContainsAll(err.Error(), "domainmappings.serving.knative.dev", "\"foo.bar\"", "not", "found"))
+
+	servingRecorder.Validate()
+}
+
+func TestDomainMappingUpdateDeletingError(t *testing.T) {
+	client := v1alpha1.NewMockKnServiceClient(t)
+
+	deletingDM := createDomainMapping("foo.bar", createServiceRef("foo", "default"))
+	deletingDM.DeletionTimestamp = &v1.Time{Time: time.Now()}
+
+	servingRecorder := client.Recorder()
+	servingRecorder.GetDomainMapping("foo.bar", deletingDM, nil)
+
+	_, err := executeDomainCommand(client, nil, "update", "foo.bar", "--ref", "bar")
+	assert.ErrorContains(t, err, "deletion")
+	assert.Assert(t, util.ContainsAll(err.Error(), "can't", "update", "domain", "mapping", "foo.bar", "marked", "deletion"))
+
+	servingRecorder.Validate()
+}
diff --git a/pkg/kn/commands/types_test.go b/pkg/kn/commands/types_test.go
index 2c725e16..90ff507c 100644
--- a/pkg/kn/commands/types_test.go
+++ b/pkg/kn/commands/types_test.go
@@ -208,6 +208,56 @@ func TestNewSourcesClient(t *testing.T) {
 	}
 }
 
+func TestNewServingV1alpha1Clients(t *testing.T) {
+	basic, err := clientcmd.NewClientConfigFromBytes([]byte(BASIC_KUBECONFIG))
+	namespace := "test"
+	if err != nil {
+		t.Error(err)
+	}
+	for i, tc := range []configTestCase{
+		{
+			clientcmd.NewDefaultClientConfig(clientcmdapi.Config{}, &clientcmd.ConfigOverrides{}),
+			"no kubeconfig has been provided, please use a valid configuration to connect to the cluster",
+			false,
+		},
+		{
+			basic,
+			"",
+			false,
+		},
+		{ // Test that the cast to wrap the http client in a logger works
+			basic,
+			"",
+			true,
+		},
+	} {
+		p := &KnParams{
+			ClientConfig: tc.clientConfig,
+			LogHTTP:      tc.logHttp,
+		}
+
+		servingV1alpha1Client, err := p.newServingClientV1alpha1(namespace)
+
+		switch len(tc.expectedErrString) {
+		case 0:
+			if err != nil {
+				t.Errorf("%d: unexpected error: %s", i, err.Error())
+			}
+		default:
+			if err == nil {
+				t.Errorf("%d: wrong error detected: %s (expected) != %s (actual)", i, tc.expectedErrString, err)
+			}
+			if !strings.Contains(err.Error(), tc.expectedErrString) {
+				t.Errorf("%d: wrong error detected: %s (expected) != %s (actual)", i, tc.expectedErrString, err.Error())
+			}
+		}
+
+		if servingV1alpha1Client != nil {
+			assert.Assert(t, servingV1alpha1Client.Namespace() == namespace)
+		}
+	}
+}
+
 func TestNewDynamicClient(t *testing.T) {
 	basic, err := clientcmd.NewClientConfigFromBytes([]byte(BASIC_KUBECONFIG))
 	namespace := "test"
diff --git a/pkg/serving/v1alpha1/client_mock_test.go b/pkg/serving/v1alpha1/client_mock_test.go
new file mode 100644
index 00000000..c819e7c0
--- /dev/null
+++ b/pkg/serving/v1alpha1/client_mock_test.go
@@ -0,0 +1,47 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1alpha1
+
+import (
+	"context"
+	"testing"
+
+	"knative.dev/serving/pkg/apis/serving/v1alpha1"
+)
+
+func TestMockKnClient(t *testing.T) {
+
+	client := NewMockKnServiceClient(t)
+
+	recorder := client.Recorder()
+
+	// Record all services
+	recorder.GetDomainMapping("hello.foo.bar", &v1alpha1.DomainMapping{}, nil)
+	recorder.CreateDomainMapping(&v1alpha1.DomainMapping{}, nil)
+	recorder.DeleteDomainMapping("hello.foo.bar", nil)
+	recorder.UpdateDomainMapping(&v1alpha1.DomainMapping{}, nil)
+	recorder.ListDomainMappings(&v1alpha1.DomainMappingList{}, nil)
+
+	// Call all services
+	ctx := context.Background()
+	client.GetDomainMapping(ctx, "hello.foo.bar")
+	client.CreateDomainMapping(ctx, &v1alpha1.DomainMapping{})
+	client.DeleteDomainMapping(ctx, "hello.foo.bar")
+	client.UpdateDomainMapping(ctx, &v1alpha1.DomainMapping{})
+	client.ListDomainMappings(ctx)
+
+	// Validate
+	recorder.Validate()
+}
diff --git a/pkg/serving/v1alpha1/client_test.go b/pkg/serving/v1alpha1/client_test.go
new file mode 100644
index 00000000..63c0a1dd
--- /dev/null
+++ b/pkg/serving/v1alpha1/client_test.go
@@ -0,0 +1,212 @@
+// Copyright © 2021 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1alpha1
+
+import (
+	"context"
+	"fmt"
+	"testing"
+
+	"gotest.tools/v3/assert"
+
+	"k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	clienttesting "k8s.io/client-go/testing"
+
+	"knative.dev/client/pkg/util"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+	servingv1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+	"knative.dev/serving/pkg/client/clientset/versioned/scheme"
+	servingv1alpha1fake "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake"
+)
+
+const (
+	testNamespace         = "test-ns"
+	domainMappingResource = "domainmappings"
+)
+
+func setup() (serving servingv1alpha1fake.FakeServingV1alpha1, client KnServingClient) {
+	serving = servingv1alpha1fake.FakeServingV1alpha1{Fake: &clienttesting.Fake{}}
+	client = NewKnServingClient(&serving, testNamespace)
+	return
+}
+
+func TestGetDomainMapping(t *testing.T) {
+	serving, client := setup()
+	serviceName := "foo"
+	domainName := "foo.bar"
+
+	serving.AddReactor("get", domainMappingResource,
+		func(a clienttesting.Action) (bool, runtime.Object, error) {
+			dm := createDomainMapping(domainName, createServiceRef(serviceName, testNamespace))
+			name := a.(clienttesting.GetAction).GetName()
+
+			assert.Assert(t, name != "")
+			assert.Equal(t, testNamespace, a.GetNamespace())
+			if name == domainName {
+				return true, dm, nil
+			}
+			return true, nil, errors.NewNotFound(servingv1alpha1.Resource("dm"), name)
+		})
+
+	t.Run("get domain mapping by name returns object", func(t *testing.T) {
+		domainMapping, err := client.GetDomainMapping(context.Background(), domainName)
+		assert.NilError(t, err)
+		assert.Equal(t, domainName, domainMapping.Name, "domain mapping name should be equal")
+		validateGroupVersionKind(t, domainMapping)
+	})
+
+	t.Run("get non-existing domain mapping by name returns error", func(t *testing.T) {
+		nonExistingName := "does-not-exist"
+		service, err := client.GetDomainMapping(context.Background(), nonExistingName)
+		assert.Assert(t, service == nil, "no domain mapping should be returned")
+		assert.ErrorContains(t, err, "not found")
+		assert.ErrorContains(t, err, nonExistingName)
+	})
+}
+
+func TestCreateDomainMapping(t *testing.T) {
+	serving, client := setup()
+	serviceName := "foo"
+	domainName := "foo.bar"
+	domainMapping := createDomainMapping(domainName, createServiceRef(serviceName, testNamespace))
+	serving.AddReactor("create", domainMappingResource,
+		func(a clienttesting.Action) (bool, runtime.Object, error) {
+			assert.Equal(t, testNamespace, a.GetNamespace())
+			name := a.(clienttesting.CreateAction).GetObject().(metav1.Object).GetName()
+			if name == domainMapping.Name {
+				domainMapping.Generation = 2
+				return true, domainMapping, nil
+			}
+			return true, nil, fmt.Errorf("error while creating service %s", name)
+		})
+
+	t.Run("create domain mapping without error creates a new object", func(t *testing.T) {
+		err := client.CreateDomainMapping(context.Background(), domainMapping)
+		assert.NilError(t, err)
+		assert.Equal(t, domainMapping.Generation, int64(2))
+		validateGroupVersionKind(t, domainMapping)
+	})
+
+	t.Run("create  domain mapping with an error returns an error object", func(t *testing.T) {
+		err := client.CreateDomainMapping(context.Background(), createDomainMapping("unknown", createServiceRef(serviceName, testNamespace)))
+		assert.ErrorContains(t, err, "unknown")
+	})
+}
+
+func TestUpdateDomainMapping(t *testing.T) {
+	serving, client := setup()
+	serviceName := "foo"
+	domainName := "foo.bar"
+	domainMappingUpdate := createDomainMapping(domainName, createServiceRef(serviceName, testNamespace))
+	domainMappingUpdate.ObjectMeta.Generation = 2
+
+	serving.AddReactor("update", domainMappingResource,
+		func(a clienttesting.Action) (bool, runtime.Object, error) {
+			assert.Equal(t, testNamespace, a.GetNamespace())
+			name := a.(clienttesting.UpdateAction).GetObject().(metav1.Object).GetName()
+			if name == domainMappingUpdate.Name {
+				dmResult := createDomainMapping(domainName, createServiceRef(serviceName, testNamespace))
+				dmResult.Generation = 3
+				return true, dmResult, nil
+			}
+			return true, nil, fmt.Errorf("error while updating service %s", name)
+		})
+
+	t.Run("update domain mapping without error", func(t *testing.T) {
+		err := client.UpdateDomainMapping(context.Background(), domainMappingUpdate)
+		assert.NilError(t, err)
+		validateGroupVersionKind(t, domainMappingUpdate)
+	})
+
+	t.Run("update domain mapping with error", func(t *testing.T) {
+		err := client.UpdateDomainMapping(context.Background(), createDomainMapping("unknown", createServiceRef(serviceName, testNamespace)))
+		assert.ErrorContains(t, err, "unknown")
+	})
+}
+
+func TestDeleteDomainMapping(t *testing.T) {
+	serving, client := setup()
+	domainName := "foo.bar"
+
+	serving.AddReactor("delete", domainMappingResource,
+		func(a clienttesting.Action) (bool, runtime.Object, error) {
+			name := a.(clienttesting.DeleteAction).GetName()
+			assert.Assert(t, name != "")
+			assert.Equal(t, testNamespace, a.GetNamespace())
+			if name == domainName {
+				return true, nil, nil
+			}
+			return true, nil, errors.NewNotFound(servingv1alpha1.Resource(domainMappingResource), name)
+		})
+
+	t.Run("delete domain mapping returns no error", func(t *testing.T) {
+		err := client.DeleteDomainMapping(context.Background(), domainName)
+		assert.NilError(t, err)
+	})
+
+	t.Run("delete non-existing domain mapping returns error", func(t *testing.T) {
+		nonExistingName := "does-not-exist"
+		err := client.DeleteDomainMapping(context.Background(), nonExistingName)
+		assert.ErrorContains(t, err, "not found")
+		assert.ErrorContains(t, err, nonExistingName)
+		assert.ErrorType(t, err, &errors.StatusError{})
+	})
+}
+
+func TestListDomainMappings(t *testing.T) {
+	serving, client := setup()
+	t.Run("list domain mappings returns a list of objects", func(t *testing.T) {
+		dm1 := createDomainMapping("dm-1", createServiceRef("svc1", testNamespace))
+		dm2 := createDomainMapping("dm-2", createServiceRef("svc2", testNamespace))
+		dm3 := createDomainMapping("dm-3", createServiceRef("svc3", testNamespace))
+		serving.AddReactor("list", domainMappingResource,
+			func(a clienttesting.Action) (bool, runtime.Object, error) {
+				assert.Equal(t, testNamespace, a.GetNamespace())
+				return true, &servingv1alpha1.DomainMappingList{Items: []servingv1alpha1.DomainMapping{*dm1, *dm2, *dm3}}, nil
+			})
+		listServices, err := client.ListDomainMappings(context.Background())
+		assert.NilError(t, err)
+		assert.Assert(t, len(listServices.Items) == 3)
+		assert.Equal(t, listServices.Items[0].Name, "dm-1")
+		assert.Equal(t, listServices.Items[1].Name, "dm-2")
+		assert.Equal(t, listServices.Items[2].Name, "dm-3")
+		validateGroupVersionKind(t, listServices)
+		validateGroupVersionKind(t, &listServices.Items[0])
+		validateGroupVersionKind(t, &listServices.Items[1])
+		validateGroupVersionKind(t, &listServices.Items[2])
+	})
+}
+
+func validateGroupVersionKind(t *testing.T, obj runtime.Object) {
+	gvkExpected, err := util.GetGroupVersionKind(obj, servingv1alpha1.SchemeGroupVersion, scheme.Scheme)
+	assert.NilError(t, err)
+	gvkGiven := obj.GetObjectKind().GroupVersionKind()
+	fmt.Println(gvkGiven.String())
+	assert.Equal(t, *gvkExpected, gvkGiven, "GVK should be the same")
+}
+
+func createDomainMapping(name string, ref duckv1.KReference) *servingv1alpha1.DomainMapping {
+	return NewDomainMappingBuilder(name).Namespace("default").Reference(ref).Build()
+}
+
+func createServiceRef(service, namespace string) duckv1.KReference {
+	return duckv1.KReference{Name: service,
+		Kind:       "Service",
+		APIVersion: "serving.knative.dev/v1",
+		Namespace:  namespace,
+	}
+}
diff --git a/test/common.sh b/test/common.sh
index 4a80600d..4d706168 100755
--- a/test/common.sh
+++ b/test/common.sh
@@ -66,8 +66,18 @@ function knative_setup() {
 
   if [ "${serving_version}" = "latest" ]; then
     start_latest_knative_serving
+
+    subheader "Installing Serving extension: DomainMapping (${serving_version})"
+    kubectl apply --filename https://storage.googleapis.com/knative-nightly/serving/latest/serving-domainmapping-crds.yaml
+    kubectl apply --filename https://storage.googleapis.com/knative-nightly/serving/latest/serving-domainmapping.yaml
+    wait_until_pods_running knative-serving || return 1
   else
     start_release_knative_serving "${serving_version}"
+
+    subheader "Installing Serving extension: DomainMapping (${serving_version})"
+    kubectl apply --filename https://storage.googleapis.com/knative-releases/serving/previous/v${serving_version}/serving-domainmapping-crds.yaml
+    kubectl apply --filename https://storage.googleapis.com/knative-releases/serving/previous/v${serving_version}/serving-domainmapping.yaml
+    wait_until_pods_running knative-serving || return 1
   fi
 
   local eventing_version=${KNATIVE_EVENTING_VERSION:-latest}
diff --git a/test/e2e/domain_mapping_test.go b/test/e2e/domain_mapping_test.go
new file mode 100644
index 00000000..abd72952
--- /dev/null
+++ b/test/e2e/domain_mapping_test.go
@@ -0,0 +1,95 @@
+// Copyright 2021 The Knative Authors
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build e2e
+// +build !eventing
+
+package e2e
+
+import (
+	"testing"
+
+	"knative.dev/client/pkg/util"
+
+	"gotest.tools/v3/assert"
+
+	"knative.dev/client/lib/test"
+)
+
+func TestDomain(t *testing.T) {
+	t.Parallel()
+	it, err := test.NewKnTest()
+	assert.NilError(t, err)
+	defer func() {
+		assert.NilError(t, it.Teardown())
+	}()
+
+	r := test.NewKnRunResultCollector(t, it)
+	defer r.DumpIfFailed()
+
+	domainName := "hello.example.com"
+
+	t.Log("create domain mapping to hello ksvc")
+	test.ServiceCreate(r, "hello")
+	domainCreate(r, domainName, "hello")
+
+	t.Log("list domain mappings")
+	domainList(r, domainName)
+
+	t.Log("update domain mapping Knative service reference")
+	test.ServiceCreate(r, "foo")
+	domainUpdate(r, domainName, "foo")
+
+	t.Log("describe domain mappings")
+	domainDescribe(r, domainName)
+
+	t.Log("delete domain")
+	domainDelete(r, domainName)
+}
+
+func domainCreate(r *test.KnRunResultCollector, domainName, serviceName string, options ...string) {
+	command := []string{"domain", "create", domainName, "--ref", serviceName}
+	command = append(command, options...)
+	out := r.KnTest().Kn().Run(command...)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "domain", "mapping", serviceName, domainName, "created", "namespace", r.KnTest().Kn().Namespace()))
+}
+
+func domainUpdate(r *test.KnRunResultCollector, domainName, serviceName string, options ...string) {
+	command := []string{"domain", "update", domainName, "--ref", serviceName}
+	command = append(command, options...)
+	out := r.KnTest().Kn().Run(command...)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "domain", "mapping", domainName, "updated", "namespace", r.KnTest().Kn().Namespace()))
+}
+
+func domainDelete(r *test.KnRunResultCollector, domainName string, options ...string) {
+	command := []string{"domain", "delete", domainName}
+	command = append(command, options...)
+	out := r.KnTest().Kn().Run(command...)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "domain", "mapping", domainName, "deleted", "namespace", r.KnTest().Kn().Namespace()))
+}
+
+func domainList(r *test.KnRunResultCollector, domainName string) {
+	out := r.KnTest().Kn().Run("domain", "list")
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAll(out.Stdout, domainName))
+}
+
+func domainDescribe(r *test.KnRunResultCollector, domainName string) {
+	out := r.KnTest().Kn().Run("domain", "describe", domainName)
+	r.AssertNoError(out)
+	assert.Assert(r.T(), util.ContainsAll(out.Stdout, "Name", "Namespace", "URL", "Service"))
+}
diff --git a/vendor/knative.dev/hack/e2e-tests.sh b/vendor/knative.dev/hack/e2e-tests.sh
index 0b8548f6..c5906d61 100644
--- a/vendor/knative.dev/hack/e2e-tests.sh
+++ b/vendor/knative.dev/hack/e2e-tests.sh
@@ -37,12 +37,15 @@ function teardown_test_resources() {
 # Parameters: $1..$n - any go test flags, then directories containing the tests to run.
 function go_test_e2e() {
   local go_test_args=()
+  [[ ! " $*" == *" -tags="* ]] && go_test_args+=("-tags=e2e")
+  [[ ! " $*" == *" -count="* ]] && go_test_args+=("-count=1")
+  [[ ! " $*" == *" -race"* ]] && go_test_args+=("-race")
+
   # Remove empty args as `go test` will consider it as running tests for the current directory, which is not expected.
   for arg in "$@"; do
     [[ -n "$arg" ]] && go_test_args+=("$arg")
   done
-  [[ ! " $*" == *" -tags="* ]] && go_test_args+=("-tags=e2e")
-  report_go_test -race -count=1 "${go_test_args[@]}"
+  report_go_test "${go_test_args[@]}"
 }
 
 # Setup the test cluster for running the tests.
@@ -69,8 +72,8 @@ function setup_test_cluster() {
   # Acquire cluster admin role for the current user.
   acquire_cluster_admin_role "${k8s_cluster}"
 
-  # Setup KO_DOCKER_REPO if it is a GKE cluster. Incorporate an element of 
-  # randomness to ensure that each run properly publishes images. Don't 
+  # Setup KO_DOCKER_REPO if it is a GKE cluster. Incorporate an element of
+  # randomness to ensure that each run properly publishes images. Don't
   # owerwrite KO_DOCKER_REPO if already set.
   [ -z "${KO_DOCKER_REPO}" ] && \
     [[ "${k8s_cluster}" =~ ^gke_.* ]] && \
diff --git a/vendor/knative.dev/hack/presubmit-tests.sh b/vendor/knative.dev/hack/presubmit-tests.sh
index e873736b..fb50ac81 100644
--- a/vendor/knative.dev/hack/presubmit-tests.sh
+++ b/vendor/knative.dev/hack/presubmit-tests.sh
@@ -209,7 +209,7 @@ function run_unit_tests() {
 
 # Default unit test runner that runs all go tests in the repo.
 function default_unit_test_runner() {
-  report_go_test -race ./...
+  report_go_test -race -count 1 ./...
 }
 
 # Run integration tests. If there's no `integration_tests` function, run the