diff --git a/contrib/completions/bash/oadm b/contrib/completions/bash/oadm index 71b217822022..bfb6db4a3dff 100644 --- a/contrib/completions/bash/oadm +++ b/contrib/completions/bash/oadm @@ -2957,6 +2957,167 @@ _oadm_build-chain() noun_aliases=() } +_oadm_migrate_image-references() +{ + last_command="oadm_migrate_image-references" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_oadm_migrate_storage() +{ + last_command="oadm_migrate_storage" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_oadm_migrate() +{ + last_command="oadm_migrate" + commands=() + commands+=("image-references") + commands+=("storage") + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _oadm_create-kubeconfig() { last_command="oadm_create-kubeconfig" @@ -3843,6 +4004,7 @@ _oadm() commands+=("diagnostics") commands+=("prune") commands+=("build-chain") + commands+=("migrate") commands+=("create-kubeconfig") commands+=("create-api-client-config") commands+=("create-bootstrap-project-template") diff --git a/contrib/completions/bash/oc b/contrib/completions/bash/oc index 9242d5929b09..10a72254041b 100644 --- a/contrib/completions/bash/oc +++ b/contrib/completions/bash/oc @@ -6943,6 +6943,164 @@ _oc_adm_build-chain() noun_aliases=() } +_oc_adm_migrate_image-references() +{ + last_command="oc_adm_migrate_image-references" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_migrate_storage() +{ + last_command="oc_adm_migrate_storage" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_migrate() +{ + last_command="oc_adm_migrate" + commands=() + commands+=("image-references") + commands+=("storage") + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _oc_adm_create-kubeconfig() { last_command="oc_adm_create-kubeconfig" @@ -7768,6 +7926,7 @@ _oc_adm() commands+=("diagnostics") commands+=("prune") commands+=("build-chain") + commands+=("migrate") commands+=("create-kubeconfig") commands+=("create-api-client-config") commands+=("create-bootstrap-project-template") diff --git a/contrib/completions/bash/openshift b/contrib/completions/bash/openshift index 5a7ee7c02dfe..b092015198a8 100644 --- a/contrib/completions/bash/openshift +++ b/contrib/completions/bash/openshift @@ -3605,6 +3605,167 @@ _openshift_admin_build-chain() noun_aliases=() } +_openshift_admin_migrate_image-references() +{ + last_command="openshift_admin_migrate_image-references" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_openshift_admin_migrate_storage() +{ + last_command="openshift_admin_migrate_storage" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_openshift_admin_migrate() +{ + last_command="openshift_admin_migrate" + commands=() + commands+=("image-references") + commands+=("storage") + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _openshift_admin_create-kubeconfig() { last_command="openshift_admin_create-kubeconfig" @@ -4448,6 +4609,7 @@ _openshift_admin() commands+=("diagnostics") commands+=("prune") commands+=("build-chain") + commands+=("migrate") commands+=("create-kubeconfig") commands+=("create-api-client-config") commands+=("create-bootstrap-project-template") @@ -11206,6 +11368,167 @@ _openshift_cli_adm_build-chain() noun_aliases=() } +_openshift_cli_adm_migrate_image-references() +{ + last_command="openshift_cli_adm_migrate_image-references" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_openshift_cli_adm_migrate_storage() +{ + last_command="openshift_cli_adm_migrate_storage" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_openshift_cli_adm_migrate() +{ + last_command="openshift_cli_adm_migrate" + commands=() + commands+=("image-references") + commands+=("storage") + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _openshift_cli_adm_create-kubeconfig() { last_command="openshift_cli_adm_create-kubeconfig" @@ -12049,6 +12372,7 @@ _openshift_cli_adm() commands+=("diagnostics") commands+=("prune") commands+=("build-chain") + commands+=("migrate") commands+=("create-kubeconfig") commands+=("create-api-client-config") commands+=("create-bootstrap-project-template") diff --git a/contrib/completions/zsh/oadm b/contrib/completions/zsh/oadm index 2617f42d7a99..442b9f4fe467 100644 --- a/contrib/completions/zsh/oadm +++ b/contrib/completions/zsh/oadm @@ -3118,6 +3118,167 @@ _oadm_build-chain() noun_aliases=() } +_oadm_migrate_image-references() +{ + last_command="oadm_migrate_image-references" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_oadm_migrate_storage() +{ + last_command="oadm_migrate_storage" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_oadm_migrate() +{ + last_command="oadm_migrate" + commands=() + commands+=("image-references") + commands+=("storage") + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _oadm_create-kubeconfig() { last_command="oadm_create-kubeconfig" @@ -4004,6 +4165,7 @@ _oadm() commands+=("diagnostics") commands+=("prune") commands+=("build-chain") + commands+=("migrate") commands+=("create-kubeconfig") commands+=("create-api-client-config") commands+=("create-bootstrap-project-template") diff --git a/contrib/completions/zsh/oc b/contrib/completions/zsh/oc index d689c49a92a0..f4bf2c3c3b92 100644 --- a/contrib/completions/zsh/oc +++ b/contrib/completions/zsh/oc @@ -7104,6 +7104,164 @@ _oc_adm_build-chain() noun_aliases=() } +_oc_adm_migrate_image-references() +{ + last_command="oc_adm_migrate_image-references" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_migrate_storage() +{ + last_command="oc_adm_migrate_storage" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_migrate() +{ + last_command="oc_adm_migrate" + commands=() + commands+=("image-references") + commands+=("storage") + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _oc_adm_create-kubeconfig() { last_command="oc_adm_create-kubeconfig" @@ -7929,6 +8087,7 @@ _oc_adm() commands+=("diagnostics") commands+=("prune") commands+=("build-chain") + commands+=("migrate") commands+=("create-kubeconfig") commands+=("create-api-client-config") commands+=("create-bootstrap-project-template") diff --git a/contrib/completions/zsh/openshift b/contrib/completions/zsh/openshift index ece939ca8447..051e0bea7461 100644 --- a/contrib/completions/zsh/openshift +++ b/contrib/completions/zsh/openshift @@ -3766,6 +3766,167 @@ _openshift_admin_build-chain() noun_aliases=() } +_openshift_admin_migrate_image-references() +{ + last_command="openshift_admin_migrate_image-references" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_openshift_admin_migrate_storage() +{ + last_command="openshift_admin_migrate_storage" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_openshift_admin_migrate() +{ + last_command="openshift_admin_migrate" + commands=() + commands+=("image-references") + commands+=("storage") + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _openshift_admin_create-kubeconfig() { last_command="openshift_admin_create-kubeconfig" @@ -4609,6 +4770,7 @@ _openshift_admin() commands+=("diagnostics") commands+=("prune") commands+=("build-chain") + commands+=("migrate") commands+=("create-kubeconfig") commands+=("create-api-client-config") commands+=("create-bootstrap-project-template") @@ -11367,6 +11529,167 @@ _openshift_cli_adm_build-chain() noun_aliases=() } +_openshift_cli_adm_migrate_image-references() +{ + last_command="openshift_cli_adm_migrate_image-references" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_openshift_cli_adm_migrate_storage() +{ + last_command="openshift_cli_adm_migrate_storage" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--confirm") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") + flags+=("--from-key=") + flags+=("--include=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--to-key=") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_flag+=("--filename=") + must_have_one_flag+=("-f") + must_have_one_noun=() + noun_aliases=() +} + +_openshift_cli_adm_migrate() +{ + last_command="openshift_cli_adm_migrate" + commands=() + commands+=("image-references") + commands+=("storage") + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--google-json-key=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--loglevel=") + flags+=("--logspec=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _openshift_cli_adm_create-kubeconfig() { last_command="openshift_cli_adm_create-kubeconfig" @@ -12210,6 +12533,7 @@ _openshift_cli_adm() commands+=("diagnostics") commands+=("prune") commands+=("build-chain") + commands+=("migrate") commands+=("create-kubeconfig") commands+=("create-api-client-config") commands+=("create-bootstrap-project-template") diff --git a/docs/generated/oadm_by_example_content.adoc b/docs/generated/oadm_by_example_content.adoc index b179017e0dcf..048a39f3b355 100644 --- a/docs/generated/oadm_by_example_content.adoc +++ b/docs/generated/oadm_by_example_content.adoc @@ -353,6 +353,54 @@ Manage nodes - list pods, evacuate, or mark ready ==== +== oadm migrate image-references +Update embedded Docker image references + +==== + +[options="nowrap"] +---- + # Perform a dry-run of migrating all "docker.io" references to "myregistry.com" + oadm migrate image-references docker.io/*=myregistry.com/* + + # To actually perform the migration, the confirm flag must be appended + oadm migrate image-references docker.io/*=myregistry.com/* --confirm + + # To see more details of what will be migrated, use the loglevel and output flags + oadm migrate image-references docker.io/*=myregistry.com/* --loglevel=2 -o yaml + + # Migrate from a service IP to an internal service DNS name + oadm migrate image-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* + + # Migrate from a service IP to an internal service DNS name for all deployment configs and builds + oadm migrate image-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* --include=buildconfigs,deploymentconfigs +---- +==== + + +== oadm migrate storage +Update the stored version of API objects + +==== + +[options="nowrap"] +---- + # Perform a dry-run of updating all objects + oadm migrate storage + + # To actually perform the update, the confirm flag must be appended + oadm migrate storage --confirm + + # Only migrate pods + oadm migrate storage --include=pods --confirm + + # Only pods that are in namespaces starting with "bar" + oadm migrate storage --include=pods --confirm --from-key=bar/ --to-key=bar/\xFF + +---- +==== + + == oadm pod-network join-projects Join project network diff --git a/docs/generated/oc_by_example_content.adoc b/docs/generated/oc_by_example_content.adoc index dbb3a0086d7a..3cfc4183992b 100644 --- a/docs/generated/oc_by_example_content.adoc +++ b/docs/generated/oc_by_example_content.adoc @@ -353,6 +353,54 @@ Manage nodes - list pods, evacuate, or mark ready ==== +== oc adm migrate image-references +Update embedded Docker image references + +==== + +[options="nowrap"] +---- + # Perform a dry-run of migrating all "docker.io" references to "myregistry.com" + oc adm migrate image-references docker.io/*=myregistry.com/* + + # To actually perform the migration, the confirm flag must be appended + oc adm migrate image-references docker.io/*=myregistry.com/* --confirm + + # To see more details of what will be migrated, use the loglevel and output flags + oc adm migrate image-references docker.io/*=myregistry.com/* --loglevel=2 -o yaml + + # Migrate from a service IP to an internal service DNS name + oc adm migrate image-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* + + # Migrate from a service IP to an internal service DNS name for all deployment configs and builds + oc adm migrate image-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* --include=buildconfigs,deploymentconfigs +---- +==== + + +== oc adm migrate storage +Update the stored version of API objects + +==== + +[options="nowrap"] +---- + # Perform a dry-run of updating all objects + oc adm migrate storage + + # To actually perform the update, the confirm flag must be appended + oc adm migrate storage --confirm + + # Only migrate pods + oc adm migrate storage --include=pods --confirm + + # Only pods that are in namespaces starting with "bar" + oc adm migrate storage --include=pods --confirm --from-key=bar/ --to-key=bar/\xFF + +---- +==== + + == oc adm pod-network join-projects Join project network diff --git a/docs/man/man1/.files_generated_oadm b/docs/man/man1/.files_generated_oadm index 409abac715ef..37ce35adbb44 100644 --- a/docs/man/man1/.files_generated_oadm +++ b/docs/man/man1/.files_generated_oadm @@ -39,6 +39,9 @@ oadm-groups-sync.1 oadm-groups.1 oadm-ipfailover.1 oadm-manage-node.1 +oadm-migrate-image-references.1 +oadm-migrate-storage.1 +oadm-migrate.1 oadm-new-project.1 oadm-options.1 oadm-overwrite-policy.1 diff --git a/docs/man/man1/.files_generated_oc b/docs/man/man1/.files_generated_oc index 6cd3df38f644..8b1b8b2534dc 100644 --- a/docs/man/man1/.files_generated_oc +++ b/docs/man/man1/.files_generated_oc @@ -39,6 +39,9 @@ oc-adm-groups-sync.1 oc-adm-groups.1 oc-adm-ipfailover.1 oc-adm-manage-node.1 +oc-adm-migrate-image-references.1 +oc-adm-migrate-storage.1 +oc-adm-migrate.1 oc-adm-new-project.1 oc-adm-options.1 oc-adm-overwrite-policy.1 diff --git a/docs/man/man1/.files_generated_openshift b/docs/man/man1/.files_generated_openshift index 6bf0e1cfd060..535e9e014e1e 100644 --- a/docs/man/man1/.files_generated_openshift +++ b/docs/man/man1/.files_generated_openshift @@ -39,6 +39,9 @@ openshift-admin-groups-sync.1 openshift-admin-groups.1 openshift-admin-ipfailover.1 openshift-admin-manage-node.1 +openshift-admin-migrate-image-references.1 +openshift-admin-migrate-storage.1 +openshift-admin-migrate.1 openshift-admin-new-project.1 openshift-admin-options.1 openshift-admin-overwrite-policy.1 @@ -115,6 +118,9 @@ openshift-cli-adm-groups-sync.1 openshift-cli-adm-groups.1 openshift-cli-adm-ipfailover.1 openshift-cli-adm-manage-node.1 +openshift-cli-adm-migrate-image-references.1 +openshift-cli-adm-migrate-storage.1 +openshift-cli-adm-migrate.1 openshift-cli-adm-new-project.1 openshift-cli-adm-options.1 openshift-cli-adm-overwrite-policy.1 diff --git a/docs/man/man1/oadm-migrate-image-references.1 b/docs/man/man1/oadm-migrate-image-references.1 new file mode 100644 index 000000000000..703a53152381 --- /dev/null +++ b/docs/man/man1/oadm-migrate-image-references.1 @@ -0,0 +1,176 @@ +.TH "OADM MIGRATE" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +oadm migrate image\-references \- Update embedded Docker image references + + +.SH SYNOPSIS +.PP +\fBoadm migrate image\-references\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate references to Docker images + +.PP +This command updates embedded Docker image references on the server in place. By default it +will update image streams and images, and may be used to update resources with a pod template +(deployments, replication controllers, daemon sets). + +.PP +References are changed by providing a mapping between a source registry and name and the +desired registry and name. Either name or registry can be set to '*' to change all values. +The registry value "docker.io" is special and will handle any image reference that refers to +the DockerHub. You may pass multiple mappings \- the first matching mapping will be applied +per resource. + +.PP +The following resource types may be migrated by this command: +.IP + +.IP +\(bu images * daemonsets +.IP +\(bu imagestreams * jobs +.IP +\(bu buildconfigs * replicationcontrollers +.IP +\(bu deploymentconfigs * pods +.IP +\(bu secrets (docker) +.PP +Only images, imagestreams, and secrets are updated by default. Updating images and image +streams requires administrative privileges. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=true + Migrate objects in all namespaces. Defaults to true. + +.PP +\fB\-\-confirm\fP=false + If true, all requested objects will be migrated. Defaults to false. + +.PP +\fB\-f\fP, \fB\-\-filename\fP=[] + Filename, directory, or URL to docker\-compose.yml file to use + +.PP +\fB\-\-from\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value + +.PP +\fB\-\-include\fP=[imagestream,image,secrets] + Resource types to migrate. Passing \-\-filename will override this flag. + +.PP +\fB\-o\fP, \fB\-\-output\fP="" + Output the modified objects instead of saving them, valid values are 'yaml' or 'json' + +.PP +\fB\-\-to\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) less than this value + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH EXAMPLE +.PP +.RS + +.nf + # Perform a dry\-run of migrating all "docker.io" references to "myregistry.com" + oadm migrate image\-references docker.io/*=myregistry.com/* + + # To actually perform the migration, the confirm flag must be appended + oadm migrate image\-references docker.io/*=myregistry.com/* \-\-confirm + + # To see more details of what will be migrated, use the loglevel and output flags + oadm migrate image\-references docker.io/*=myregistry.com/* \-\-loglevel=2 \-o yaml + + # Migrate from a service IP to an internal service DNS name + oadm migrate image\-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* + + # Migrate from a service IP to an internal service DNS name for all deployment configs and builds + oadm migrate image\-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* \-\-include=buildconfigs,deploymentconfigs + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBoadm\-migrate(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/oadm-migrate-storage.1 b/docs/man/man1/oadm-migrate-storage.1 new file mode 100644 index 000000000000..8eafb221671d --- /dev/null +++ b/docs/man/man1/oadm-migrate-storage.1 @@ -0,0 +1,165 @@ +.TH "OADM MIGRATE" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +oadm migrate storage \- Update the stored version of API objects + + +.SH SYNOPSIS +.PP +\fBoadm migrate storage\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate internal object storage via update + +.PP +This command invokes an update operation on every API object reachable by the caller. This forces +the server to write to the underlying storage if the object representation has changed. Use this +command to ensure that the most recent storage changes have been applied to all objects (storage +version, storage encoding, any newer object defaults). + +.PP +To operate on a subset of resources, use the \-\-include flag. If you encounter errors during a run +the command will output a list of resources that received errors, which you can then re\-run the +command on. You may also specify \-\-from\-key and \-\-to\-key to restrict the set of resource names +to operate on (key is NAMESPACE/NAME for resources in namespaces or NAME for cluster scoped +resources). \-\-from\-key is inclusive if specified, while \-\-to\-key is exclusive. + +.PP +By default, events are not migrated since they expire within a very short period of time. If you +have significantly increased the expiration time of events, run a migration with \-\-include=events + +.PP +WARNING: This is a slow command and will put significant load on an API server. It may also + result in significant intra\-cluster traffic. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=true + Migrate objects in all namespaces. Defaults to true. + +.PP +\fB\-\-confirm\fP=false + If true, all requested objects will be migrated. Defaults to false. + +.PP +\fB\-f\fP, \fB\-\-filename\fP=[] + Filename, directory, or URL to docker\-compose.yml file to use + +.PP +\fB\-\-from\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value + +.PP +\fB\-\-include\fP=[*] + Resource types to migrate. Passing \-\-filename will override this flag. + +.PP +\fB\-o\fP, \fB\-\-output\fP="" + Output the modified objects instead of saving them, valid values are 'yaml' or 'json' + +.PP +\fB\-\-to\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) less than this value + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH EXAMPLE +.PP +.RS + +.nf + # Perform a dry\-run of updating all objects + oadm migrate storage + + # To actually perform the update, the confirm flag must be appended + oadm migrate storage \-\-confirm + + # Only migrate pods + oadm migrate storage \-\-include=pods \-\-confirm + + # Only pods that are in namespaces starting with "bar" + oadm migrate storage \-\-include=pods \-\-confirm \-\-from\-key=bar/ \-\-to\-key=bar/\\xFF + + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBoadm\-migrate(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/oadm-migrate.1 b/docs/man/man1/oadm-migrate.1 new file mode 100644 index 000000000000..857824eb0712 --- /dev/null +++ b/docs/man/man1/oadm-migrate.1 @@ -0,0 +1,95 @@ +.TH "OADM" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +oadm migrate \- Migrate data in the cluster + + +.SH SYNOPSIS +.PP +\fBoadm migrate\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate resources on the cluster + +.PP +These commands assist administrators in performing preventative maintenance on a cluster. + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH SEE ALSO +.PP +\fBoadm(1)\fP, \fBoadm\-migrate\-image\-references(1)\fP, \fBoadm\-migrate\-storage(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/oadm.1 b/docs/man/man1/oadm.1 index a8c1ad4e041b..6e3292a14568 100644 --- a/docs/man/man1/oadm.1 +++ b/docs/man/man1/oadm.1 @@ -88,7 +88,7 @@ actions involve interaction with the command\-line client as well. .SH SEE ALSO .PP -\fBoadm\-router(1)\fP, \fBoadm\-ipfailover(1)\fP, \fBoadm\-registry(1)\fP, \fBoadm\-new\-project(1)\fP, \fBoadm\-policy(1)\fP, \fBoadm\-groups(1)\fP, \fBoadm\-ca(1)\fP, \fBoadm\-overwrite\-policy(1)\fP, \fBoadm\-create\-node\-config(1)\fP, \fBoadm\-manage\-node(1)\fP, \fBoadm\-cordon(1)\fP, \fBoadm\-uncordon(1)\fP, \fBoadm\-drain(1)\fP, \fBoadm\-taint(1)\fP, \fBoadm\-pod\-network(1)\fP, \fBoadm\-diagnostics(1)\fP, \fBoadm\-prune(1)\fP, \fBoadm\-build\-chain(1)\fP, \fBoadm\-create\-kubeconfig(1)\fP, \fBoadm\-create\-api\-client\-config(1)\fP, \fBoadm\-create\-bootstrap\-project\-template(1)\fP, \fBoadm\-create\-bootstrap\-policy\-file(1)\fP, \fBoadm\-create\-login\-template(1)\fP, \fBoadm\-create\-provider\-selection\-template(1)\fP, \fBoadm\-create\-error\-template(1)\fP, \fBoadm\-create\-master\-certs(1)\fP, \fBoadm\-create\-key\-pair(1)\fP, \fBoadm\-create\-server\-cert(1)\fP, \fBoadm\-create\-signer\-cert(1)\fP, \fBoadm\-config(1)\fP, \fBoadm\-completion(1)\fP, \fBoadm\-options(1)\fP, \fBoadm\-version(1)\fP, +\fBoadm\-router(1)\fP, \fBoadm\-ipfailover(1)\fP, \fBoadm\-registry(1)\fP, \fBoadm\-new\-project(1)\fP, \fBoadm\-policy(1)\fP, \fBoadm\-groups(1)\fP, \fBoadm\-ca(1)\fP, \fBoadm\-overwrite\-policy(1)\fP, \fBoadm\-create\-node\-config(1)\fP, \fBoadm\-manage\-node(1)\fP, \fBoadm\-cordon(1)\fP, \fBoadm\-uncordon(1)\fP, \fBoadm\-drain(1)\fP, \fBoadm\-taint(1)\fP, \fBoadm\-pod\-network(1)\fP, \fBoadm\-diagnostics(1)\fP, \fBoadm\-prune(1)\fP, \fBoadm\-build\-chain(1)\fP, \fBoadm\-migrate(1)\fP, \fBoadm\-create\-kubeconfig(1)\fP, \fBoadm\-create\-api\-client\-config(1)\fP, \fBoadm\-create\-bootstrap\-project\-template(1)\fP, \fBoadm\-create\-bootstrap\-policy\-file(1)\fP, \fBoadm\-create\-login\-template(1)\fP, \fBoadm\-create\-provider\-selection\-template(1)\fP, \fBoadm\-create\-error\-template(1)\fP, \fBoadm\-create\-master\-certs(1)\fP, \fBoadm\-create\-key\-pair(1)\fP, \fBoadm\-create\-server\-cert(1)\fP, \fBoadm\-create\-signer\-cert(1)\fP, \fBoadm\-config(1)\fP, \fBoadm\-completion(1)\fP, \fBoadm\-options(1)\fP, \fBoadm\-version(1)\fP, .SH HISTORY diff --git a/docs/man/man1/oc-adm-migrate-image-references.1 b/docs/man/man1/oc-adm-migrate-image-references.1 new file mode 100644 index 000000000000..e3dd0c4d1f56 --- /dev/null +++ b/docs/man/man1/oc-adm-migrate-image-references.1 @@ -0,0 +1,176 @@ +.TH "OC ADM MIGRATE" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +oc adm migrate image\-references \- Update embedded Docker image references + + +.SH SYNOPSIS +.PP +\fBoc adm migrate image\-references\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate references to Docker images + +.PP +This command updates embedded Docker image references on the server in place. By default it +will update image streams and images, and may be used to update resources with a pod template +(deployments, replication controllers, daemon sets). + +.PP +References are changed by providing a mapping between a source registry and name and the +desired registry and name. Either name or registry can be set to '*' to change all values. +The registry value "docker.io" is special and will handle any image reference that refers to +the DockerHub. You may pass multiple mappings \- the first matching mapping will be applied +per resource. + +.PP +The following resource types may be migrated by this command: +.IP + +.IP +\(bu images * daemonsets +.IP +\(bu imagestreams * jobs +.IP +\(bu buildconfigs * replicationcontrollers +.IP +\(bu deploymentconfigs * pods +.IP +\(bu secrets (docker) +.PP +Only images, imagestreams, and secrets are updated by default. Updating images and image +streams requires administrative privileges. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=true + Migrate objects in all namespaces. Defaults to true. + +.PP +\fB\-\-confirm\fP=false + If true, all requested objects will be migrated. Defaults to false. + +.PP +\fB\-f\fP, \fB\-\-filename\fP=[] + Filename, directory, or URL to docker\-compose.yml file to use + +.PP +\fB\-\-from\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value + +.PP +\fB\-\-include\fP=[imagestream,image,secrets] + Resource types to migrate. Passing \-\-filename will override this flag. + +.PP +\fB\-o\fP, \fB\-\-output\fP="" + Output the modified objects instead of saving them, valid values are 'yaml' or 'json' + +.PP +\fB\-\-to\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) less than this value + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH EXAMPLE +.PP +.RS + +.nf + # Perform a dry\-run of migrating all "docker.io" references to "myregistry.com" + oc adm migrate image\-references docker.io/*=myregistry.com/* + + # To actually perform the migration, the confirm flag must be appended + oc adm migrate image\-references docker.io/*=myregistry.com/* \-\-confirm + + # To see more details of what will be migrated, use the loglevel and output flags + oc adm migrate image\-references docker.io/*=myregistry.com/* \-\-loglevel=2 \-o yaml + + # Migrate from a service IP to an internal service DNS name + oc adm migrate image\-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* + + # Migrate from a service IP to an internal service DNS name for all deployment configs and builds + oc adm migrate image\-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* \-\-include=buildconfigs,deploymentconfigs + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBoc\-adm\-migrate(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/oc-adm-migrate-storage.1 b/docs/man/man1/oc-adm-migrate-storage.1 new file mode 100644 index 000000000000..cf30f586b629 --- /dev/null +++ b/docs/man/man1/oc-adm-migrate-storage.1 @@ -0,0 +1,165 @@ +.TH "OC ADM MIGRATE" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +oc adm migrate storage \- Update the stored version of API objects + + +.SH SYNOPSIS +.PP +\fBoc adm migrate storage\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate internal object storage via update + +.PP +This command invokes an update operation on every API object reachable by the caller. This forces +the server to write to the underlying storage if the object representation has changed. Use this +command to ensure that the most recent storage changes have been applied to all objects (storage +version, storage encoding, any newer object defaults). + +.PP +To operate on a subset of resources, use the \-\-include flag. If you encounter errors during a run +the command will output a list of resources that received errors, which you can then re\-run the +command on. You may also specify \-\-from\-key and \-\-to\-key to restrict the set of resource names +to operate on (key is NAMESPACE/NAME for resources in namespaces or NAME for cluster scoped +resources). \-\-from\-key is inclusive if specified, while \-\-to\-key is exclusive. + +.PP +By default, events are not migrated since they expire within a very short period of time. If you +have significantly increased the expiration time of events, run a migration with \-\-include=events + +.PP +WARNING: This is a slow command and will put significant load on an API server. It may also + result in significant intra\-cluster traffic. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=true + Migrate objects in all namespaces. Defaults to true. + +.PP +\fB\-\-confirm\fP=false + If true, all requested objects will be migrated. Defaults to false. + +.PP +\fB\-f\fP, \fB\-\-filename\fP=[] + Filename, directory, or URL to docker\-compose.yml file to use + +.PP +\fB\-\-from\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value + +.PP +\fB\-\-include\fP=[*] + Resource types to migrate. Passing \-\-filename will override this flag. + +.PP +\fB\-o\fP, \fB\-\-output\fP="" + Output the modified objects instead of saving them, valid values are 'yaml' or 'json' + +.PP +\fB\-\-to\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) less than this value + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH EXAMPLE +.PP +.RS + +.nf + # Perform a dry\-run of updating all objects + oc adm migrate storage + + # To actually perform the update, the confirm flag must be appended + oc adm migrate storage \-\-confirm + + # Only migrate pods + oc adm migrate storage \-\-include=pods \-\-confirm + + # Only pods that are in namespaces starting with "bar" + oc adm migrate storage \-\-include=pods \-\-confirm \-\-from\-key=bar/ \-\-to\-key=bar/\\xFF + + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBoc\-adm\-migrate(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/oc-adm-migrate.1 b/docs/man/man1/oc-adm-migrate.1 new file mode 100644 index 000000000000..f61363d2cf9e --- /dev/null +++ b/docs/man/man1/oc-adm-migrate.1 @@ -0,0 +1,95 @@ +.TH "OC ADM" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +oc adm migrate \- Migrate data in the cluster + + +.SH SYNOPSIS +.PP +\fBoc adm migrate\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate resources on the cluster + +.PP +These commands assist administrators in performing preventative maintenance on a cluster. + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH SEE ALSO +.PP +\fBoc\-adm(1)\fP, \fBoc\-adm\-migrate\-image\-references(1)\fP, \fBoc\-adm\-migrate\-storage(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/oc-adm.1 b/docs/man/man1/oc-adm.1 index a6de9e61dc43..98708d8a9037 100644 --- a/docs/man/man1/oc-adm.1 +++ b/docs/man/man1/oc-adm.1 @@ -90,7 +90,7 @@ actions involve interaction with the command\-line client as well. .SH SEE ALSO .PP -\fBoc(1)\fP, \fBoc\-adm\-router(1)\fP, \fBoc\-adm\-ipfailover(1)\fP, \fBoc\-adm\-registry(1)\fP, \fBoc\-adm\-new\-project(1)\fP, \fBoc\-adm\-policy(1)\fP, \fBoc\-adm\-groups(1)\fP, \fBoc\-adm\-ca(1)\fP, \fBoc\-adm\-overwrite\-policy(1)\fP, \fBoc\-adm\-create\-node\-config(1)\fP, \fBoc\-adm\-manage\-node(1)\fP, \fBoc\-adm\-cordon(1)\fP, \fBoc\-adm\-uncordon(1)\fP, \fBoc\-adm\-drain(1)\fP, \fBoc\-adm\-taint(1)\fP, \fBoc\-adm\-pod\-network(1)\fP, \fBoc\-adm\-diagnostics(1)\fP, \fBoc\-adm\-prune(1)\fP, \fBoc\-adm\-build\-chain(1)\fP, \fBoc\-adm\-create\-kubeconfig(1)\fP, \fBoc\-adm\-create\-api\-client\-config(1)\fP, \fBoc\-adm\-create\-bootstrap\-project\-template(1)\fP, \fBoc\-adm\-create\-bootstrap\-policy\-file(1)\fP, \fBoc\-adm\-create\-login\-template(1)\fP, \fBoc\-adm\-create\-provider\-selection\-template(1)\fP, \fBoc\-adm\-create\-error\-template(1)\fP, \fBoc\-adm\-create\-master\-certs(1)\fP, \fBoc\-adm\-create\-key\-pair(1)\fP, \fBoc\-adm\-create\-server\-cert(1)\fP, \fBoc\-adm\-create\-signer\-cert(1)\fP, \fBoc\-adm\-config(1)\fP, \fBoc\-adm\-completion(1)\fP, \fBoc\-adm\-options(1)\fP, +\fBoc(1)\fP, \fBoc\-adm\-router(1)\fP, \fBoc\-adm\-ipfailover(1)\fP, \fBoc\-adm\-registry(1)\fP, \fBoc\-adm\-new\-project(1)\fP, \fBoc\-adm\-policy(1)\fP, \fBoc\-adm\-groups(1)\fP, \fBoc\-adm\-ca(1)\fP, \fBoc\-adm\-overwrite\-policy(1)\fP, \fBoc\-adm\-create\-node\-config(1)\fP, \fBoc\-adm\-manage\-node(1)\fP, \fBoc\-adm\-cordon(1)\fP, \fBoc\-adm\-uncordon(1)\fP, \fBoc\-adm\-drain(1)\fP, \fBoc\-adm\-taint(1)\fP, \fBoc\-adm\-pod\-network(1)\fP, \fBoc\-adm\-diagnostics(1)\fP, \fBoc\-adm\-prune(1)\fP, \fBoc\-adm\-build\-chain(1)\fP, \fBoc\-adm\-migrate(1)\fP, \fBoc\-adm\-create\-kubeconfig(1)\fP, \fBoc\-adm\-create\-api\-client\-config(1)\fP, \fBoc\-adm\-create\-bootstrap\-project\-template(1)\fP, \fBoc\-adm\-create\-bootstrap\-policy\-file(1)\fP, \fBoc\-adm\-create\-login\-template(1)\fP, \fBoc\-adm\-create\-provider\-selection\-template(1)\fP, \fBoc\-adm\-create\-error\-template(1)\fP, \fBoc\-adm\-create\-master\-certs(1)\fP, \fBoc\-adm\-create\-key\-pair(1)\fP, \fBoc\-adm\-create\-server\-cert(1)\fP, \fBoc\-adm\-create\-signer\-cert(1)\fP, \fBoc\-adm\-config(1)\fP, \fBoc\-adm\-completion(1)\fP, \fBoc\-adm\-options(1)\fP, .SH HISTORY diff --git a/docs/man/man1/openshift-admin-migrate-image-references.1 b/docs/man/man1/openshift-admin-migrate-image-references.1 new file mode 100644 index 000000000000..b142bede6193 --- /dev/null +++ b/docs/man/man1/openshift-admin-migrate-image-references.1 @@ -0,0 +1,176 @@ +.TH "OPENSHIFT ADMIN MIGRATE" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +openshift admin migrate image\-references \- Update embedded Docker image references + + +.SH SYNOPSIS +.PP +\fBopenshift admin migrate image\-references\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate references to Docker images + +.PP +This command updates embedded Docker image references on the server in place. By default it +will update image streams and images, and may be used to update resources with a pod template +(deployments, replication controllers, daemon sets). + +.PP +References are changed by providing a mapping between a source registry and name and the +desired registry and name. Either name or registry can be set to '*' to change all values. +The registry value "docker.io" is special and will handle any image reference that refers to +the DockerHub. You may pass multiple mappings \- the first matching mapping will be applied +per resource. + +.PP +The following resource types may be migrated by this command: +.IP + +.IP +\(bu images * daemonsets +.IP +\(bu imagestreams * jobs +.IP +\(bu buildconfigs * replicationcontrollers +.IP +\(bu deploymentconfigs * pods +.IP +\(bu secrets (docker) +.PP +Only images, imagestreams, and secrets are updated by default. Updating images and image +streams requires administrative privileges. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=true + Migrate objects in all namespaces. Defaults to true. + +.PP +\fB\-\-confirm\fP=false + If true, all requested objects will be migrated. Defaults to false. + +.PP +\fB\-f\fP, \fB\-\-filename\fP=[] + Filename, directory, or URL to docker\-compose.yml file to use + +.PP +\fB\-\-from\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value + +.PP +\fB\-\-include\fP=[imagestream,image,secrets] + Resource types to migrate. Passing \-\-filename will override this flag. + +.PP +\fB\-o\fP, \fB\-\-output\fP="" + Output the modified objects instead of saving them, valid values are 'yaml' or 'json' + +.PP +\fB\-\-to\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) less than this value + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH EXAMPLE +.PP +.RS + +.nf + # Perform a dry\-run of migrating all "docker.io" references to "myregistry.com" + openshift admin migrate image\-references docker.io/*=myregistry.com/* + + # To actually perform the migration, the confirm flag must be appended + openshift admin migrate image\-references docker.io/*=myregistry.com/* \-\-confirm + + # To see more details of what will be migrated, use the loglevel and output flags + openshift admin migrate image\-references docker.io/*=myregistry.com/* \-\-loglevel=2 \-o yaml + + # Migrate from a service IP to an internal service DNS name + openshift admin migrate image\-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* + + # Migrate from a service IP to an internal service DNS name for all deployment configs and builds + openshift admin migrate image\-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* \-\-include=buildconfigs,deploymentconfigs + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBopenshift\-admin\-migrate(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/openshift-admin-migrate-storage.1 b/docs/man/man1/openshift-admin-migrate-storage.1 new file mode 100644 index 000000000000..8102962ea6cb --- /dev/null +++ b/docs/man/man1/openshift-admin-migrate-storage.1 @@ -0,0 +1,165 @@ +.TH "OPENSHIFT ADMIN MIGRATE" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +openshift admin migrate storage \- Update the stored version of API objects + + +.SH SYNOPSIS +.PP +\fBopenshift admin migrate storage\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate internal object storage via update + +.PP +This command invokes an update operation on every API object reachable by the caller. This forces +the server to write to the underlying storage if the object representation has changed. Use this +command to ensure that the most recent storage changes have been applied to all objects (storage +version, storage encoding, any newer object defaults). + +.PP +To operate on a subset of resources, use the \-\-include flag. If you encounter errors during a run +the command will output a list of resources that received errors, which you can then re\-run the +command on. You may also specify \-\-from\-key and \-\-to\-key to restrict the set of resource names +to operate on (key is NAMESPACE/NAME for resources in namespaces or NAME for cluster scoped +resources). \-\-from\-key is inclusive if specified, while \-\-to\-key is exclusive. + +.PP +By default, events are not migrated since they expire within a very short period of time. If you +have significantly increased the expiration time of events, run a migration with \-\-include=events + +.PP +WARNING: This is a slow command and will put significant load on an API server. It may also + result in significant intra\-cluster traffic. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=true + Migrate objects in all namespaces. Defaults to true. + +.PP +\fB\-\-confirm\fP=false + If true, all requested objects will be migrated. Defaults to false. + +.PP +\fB\-f\fP, \fB\-\-filename\fP=[] + Filename, directory, or URL to docker\-compose.yml file to use + +.PP +\fB\-\-from\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value + +.PP +\fB\-\-include\fP=[*] + Resource types to migrate. Passing \-\-filename will override this flag. + +.PP +\fB\-o\fP, \fB\-\-output\fP="" + Output the modified objects instead of saving them, valid values are 'yaml' or 'json' + +.PP +\fB\-\-to\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) less than this value + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH EXAMPLE +.PP +.RS + +.nf + # Perform a dry\-run of updating all objects + openshift admin migrate storage + + # To actually perform the update, the confirm flag must be appended + openshift admin migrate storage \-\-confirm + + # Only migrate pods + openshift admin migrate storage \-\-include=pods \-\-confirm + + # Only pods that are in namespaces starting with "bar" + openshift admin migrate storage \-\-include=pods \-\-confirm \-\-from\-key=bar/ \-\-to\-key=bar/\\xFF + + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBopenshift\-admin\-migrate(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/openshift-admin-migrate.1 b/docs/man/man1/openshift-admin-migrate.1 new file mode 100644 index 000000000000..3374dd356005 --- /dev/null +++ b/docs/man/man1/openshift-admin-migrate.1 @@ -0,0 +1,95 @@ +.TH "OPENSHIFT ADMIN" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +openshift admin migrate \- Migrate data in the cluster + + +.SH SYNOPSIS +.PP +\fBopenshift admin migrate\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate resources on the cluster + +.PP +These commands assist administrators in performing preventative maintenance on a cluster. + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH SEE ALSO +.PP +\fBopenshift\-admin(1)\fP, \fBopenshift\-admin\-migrate\-image\-references(1)\fP, \fBopenshift\-admin\-migrate\-storage(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/openshift-admin.1 b/docs/man/man1/openshift-admin.1 index 9950efeeff7c..0747d74a4a46 100644 --- a/docs/man/man1/openshift-admin.1 +++ b/docs/man/man1/openshift-admin.1 @@ -90,7 +90,7 @@ actions involve interaction with the command\-line client as well. .SH SEE ALSO .PP -\fBopenshift(1)\fP, \fBopenshift\-admin\-router(1)\fP, \fBopenshift\-admin\-ipfailover(1)\fP, \fBopenshift\-admin\-registry(1)\fP, \fBopenshift\-admin\-new\-project(1)\fP, \fBopenshift\-admin\-policy(1)\fP, \fBopenshift\-admin\-groups(1)\fP, \fBopenshift\-admin\-ca(1)\fP, \fBopenshift\-admin\-overwrite\-policy(1)\fP, \fBopenshift\-admin\-create\-node\-config(1)\fP, \fBopenshift\-admin\-manage\-node(1)\fP, \fBopenshift\-admin\-cordon(1)\fP, \fBopenshift\-admin\-uncordon(1)\fP, \fBopenshift\-admin\-drain(1)\fP, \fBopenshift\-admin\-taint(1)\fP, \fBopenshift\-admin\-pod\-network(1)\fP, \fBopenshift\-admin\-diagnostics(1)\fP, \fBopenshift\-admin\-prune(1)\fP, \fBopenshift\-admin\-build\-chain(1)\fP, \fBopenshift\-admin\-create\-kubeconfig(1)\fP, \fBopenshift\-admin\-create\-api\-client\-config(1)\fP, \fBopenshift\-admin\-create\-bootstrap\-project\-template(1)\fP, \fBopenshift\-admin\-create\-bootstrap\-policy\-file(1)\fP, \fBopenshift\-admin\-create\-login\-template(1)\fP, \fBopenshift\-admin\-create\-provider\-selection\-template(1)\fP, \fBopenshift\-admin\-create\-error\-template(1)\fP, \fBopenshift\-admin\-create\-master\-certs(1)\fP, \fBopenshift\-admin\-create\-key\-pair(1)\fP, \fBopenshift\-admin\-create\-server\-cert(1)\fP, \fBopenshift\-admin\-create\-signer\-cert(1)\fP, \fBopenshift\-admin\-config(1)\fP, \fBopenshift\-admin\-completion(1)\fP, \fBopenshift\-admin\-options(1)\fP, +\fBopenshift(1)\fP, \fBopenshift\-admin\-router(1)\fP, \fBopenshift\-admin\-ipfailover(1)\fP, \fBopenshift\-admin\-registry(1)\fP, \fBopenshift\-admin\-new\-project(1)\fP, \fBopenshift\-admin\-policy(1)\fP, \fBopenshift\-admin\-groups(1)\fP, \fBopenshift\-admin\-ca(1)\fP, \fBopenshift\-admin\-overwrite\-policy(1)\fP, \fBopenshift\-admin\-create\-node\-config(1)\fP, \fBopenshift\-admin\-manage\-node(1)\fP, \fBopenshift\-admin\-cordon(1)\fP, \fBopenshift\-admin\-uncordon(1)\fP, \fBopenshift\-admin\-drain(1)\fP, \fBopenshift\-admin\-taint(1)\fP, \fBopenshift\-admin\-pod\-network(1)\fP, \fBopenshift\-admin\-diagnostics(1)\fP, \fBopenshift\-admin\-prune(1)\fP, \fBopenshift\-admin\-build\-chain(1)\fP, \fBopenshift\-admin\-migrate(1)\fP, \fBopenshift\-admin\-create\-kubeconfig(1)\fP, \fBopenshift\-admin\-create\-api\-client\-config(1)\fP, \fBopenshift\-admin\-create\-bootstrap\-project\-template(1)\fP, \fBopenshift\-admin\-create\-bootstrap\-policy\-file(1)\fP, \fBopenshift\-admin\-create\-login\-template(1)\fP, \fBopenshift\-admin\-create\-provider\-selection\-template(1)\fP, \fBopenshift\-admin\-create\-error\-template(1)\fP, \fBopenshift\-admin\-create\-master\-certs(1)\fP, \fBopenshift\-admin\-create\-key\-pair(1)\fP, \fBopenshift\-admin\-create\-server\-cert(1)\fP, \fBopenshift\-admin\-create\-signer\-cert(1)\fP, \fBopenshift\-admin\-config(1)\fP, \fBopenshift\-admin\-completion(1)\fP, \fBopenshift\-admin\-options(1)\fP, .SH HISTORY diff --git a/docs/man/man1/openshift-cli-adm-migrate-image-references.1 b/docs/man/man1/openshift-cli-adm-migrate-image-references.1 new file mode 100644 index 000000000000..fca7dd6daaaf --- /dev/null +++ b/docs/man/man1/openshift-cli-adm-migrate-image-references.1 @@ -0,0 +1,176 @@ +.TH "OPENSHIFT CLI ADM MIGRATE" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +openshift cli adm migrate image\-references \- Update embedded Docker image references + + +.SH SYNOPSIS +.PP +\fBopenshift cli adm migrate image\-references\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate references to Docker images + +.PP +This command updates embedded Docker image references on the server in place. By default it +will update image streams and images, and may be used to update resources with a pod template +(deployments, replication controllers, daemon sets). + +.PP +References are changed by providing a mapping between a source registry and name and the +desired registry and name. Either name or registry can be set to '*' to change all values. +The registry value "docker.io" is special and will handle any image reference that refers to +the DockerHub. You may pass multiple mappings \- the first matching mapping will be applied +per resource. + +.PP +The following resource types may be migrated by this command: +.IP + +.IP +\(bu images * daemonsets +.IP +\(bu imagestreams * jobs +.IP +\(bu buildconfigs * replicationcontrollers +.IP +\(bu deploymentconfigs * pods +.IP +\(bu secrets (docker) +.PP +Only images, imagestreams, and secrets are updated by default. Updating images and image +streams requires administrative privileges. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=true + Migrate objects in all namespaces. Defaults to true. + +.PP +\fB\-\-confirm\fP=false + If true, all requested objects will be migrated. Defaults to false. + +.PP +\fB\-f\fP, \fB\-\-filename\fP=[] + Filename, directory, or URL to docker\-compose.yml file to use + +.PP +\fB\-\-from\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value + +.PP +\fB\-\-include\fP=[imagestream,image,secrets] + Resource types to migrate. Passing \-\-filename will override this flag. + +.PP +\fB\-o\fP, \fB\-\-output\fP="" + Output the modified objects instead of saving them, valid values are 'yaml' or 'json' + +.PP +\fB\-\-to\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) less than this value + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH EXAMPLE +.PP +.RS + +.nf + # Perform a dry\-run of migrating all "docker.io" references to "myregistry.com" + openshift cli adm migrate image\-references docker.io/*=myregistry.com/* + + # To actually perform the migration, the confirm flag must be appended + openshift cli adm migrate image\-references docker.io/*=myregistry.com/* \-\-confirm + + # To see more details of what will be migrated, use the loglevel and output flags + openshift cli adm migrate image\-references docker.io/*=myregistry.com/* \-\-loglevel=2 \-o yaml + + # Migrate from a service IP to an internal service DNS name + openshift cli adm migrate image\-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* + + # Migrate from a service IP to an internal service DNS name for all deployment configs and builds + openshift cli adm migrate image\-references 172.30.1.54/*=registry.openshift.svc.cluster.local/* \-\-include=buildconfigs,deploymentconfigs + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBopenshift\-cli\-adm\-migrate(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/openshift-cli-adm-migrate-storage.1 b/docs/man/man1/openshift-cli-adm-migrate-storage.1 new file mode 100644 index 000000000000..d0c34d7c94b1 --- /dev/null +++ b/docs/man/man1/openshift-cli-adm-migrate-storage.1 @@ -0,0 +1,165 @@ +.TH "OPENSHIFT CLI ADM MIGRATE" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +openshift cli adm migrate storage \- Update the stored version of API objects + + +.SH SYNOPSIS +.PP +\fBopenshift cli adm migrate storage\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate internal object storage via update + +.PP +This command invokes an update operation on every API object reachable by the caller. This forces +the server to write to the underlying storage if the object representation has changed. Use this +command to ensure that the most recent storage changes have been applied to all objects (storage +version, storage encoding, any newer object defaults). + +.PP +To operate on a subset of resources, use the \-\-include flag. If you encounter errors during a run +the command will output a list of resources that received errors, which you can then re\-run the +command on. You may also specify \-\-from\-key and \-\-to\-key to restrict the set of resource names +to operate on (key is NAMESPACE/NAME for resources in namespaces or NAME for cluster scoped +resources). \-\-from\-key is inclusive if specified, while \-\-to\-key is exclusive. + +.PP +By default, events are not migrated since they expire within a very short period of time. If you +have significantly increased the expiration time of events, run a migration with \-\-include=events + +.PP +WARNING: This is a slow command and will put significant load on an API server. It may also + result in significant intra\-cluster traffic. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=true + Migrate objects in all namespaces. Defaults to true. + +.PP +\fB\-\-confirm\fP=false + If true, all requested objects will be migrated. Defaults to false. + +.PP +\fB\-f\fP, \fB\-\-filename\fP=[] + Filename, directory, or URL to docker\-compose.yml file to use + +.PP +\fB\-\-from\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value + +.PP +\fB\-\-include\fP=[*] + Resource types to migrate. Passing \-\-filename will override this flag. + +.PP +\fB\-o\fP, \fB\-\-output\fP="" + Output the modified objects instead of saving them, valid values are 'yaml' or 'json' + +.PP +\fB\-\-to\-key\fP="" + If specified, only migrate items with a key (namespace/name or name) less than this value + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH EXAMPLE +.PP +.RS + +.nf + # Perform a dry\-run of updating all objects + openshift cli adm migrate storage + + # To actually perform the update, the confirm flag must be appended + openshift cli adm migrate storage \-\-confirm + + # Only migrate pods + openshift cli adm migrate storage \-\-include=pods \-\-confirm + + # Only pods that are in namespaces starting with "bar" + openshift cli adm migrate storage \-\-include=pods \-\-confirm \-\-from\-key=bar/ \-\-to\-key=bar/\\xFF + + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBopenshift\-cli\-adm\-migrate(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/openshift-cli-adm-migrate.1 b/docs/man/man1/openshift-cli-adm-migrate.1 new file mode 100644 index 000000000000..bf88e88526d3 --- /dev/null +++ b/docs/man/man1/openshift-cli-adm-migrate.1 @@ -0,0 +1,95 @@ +.TH "OPENSHIFT CLI ADM" "1" " Openshift CLI User Manuals" "Openshift" "June 2016" "" + + +.SH NAME +.PP +openshift cli adm migrate \- Migrate data in the cluster + + +.SH SYNOPSIS +.PP +\fBopenshift cli adm migrate\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Migrate resources on the cluster + +.PP +These commands assist administrators in performing preventative maintenance on a cluster. + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-config\fP="" + Path to the config file to use for CLI requests. + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-google\-json\-key\fP="" + The Google Cloud Platform Service Account JSON Key to use for authentication. + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-log\-flush\-frequency\fP=0 + Maximum number of seconds between log flushes + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-n\fP, \fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + + +.SH SEE ALSO +.PP +\fBopenshift\-cli\-adm(1)\fP, \fBopenshift\-cli\-adm\-migrate\-image\-references(1)\fP, \fBopenshift\-cli\-adm\-migrate\-storage(1)\fP, + + +.SH HISTORY +.PP +June 2016, Ported from the Kubernetes man\-doc generator diff --git a/docs/man/man1/openshift-cli-adm.1 b/docs/man/man1/openshift-cli-adm.1 index a263f7114ede..750d1b5054ad 100644 --- a/docs/man/man1/openshift-cli-adm.1 +++ b/docs/man/man1/openshift-cli-adm.1 @@ -90,7 +90,7 @@ actions involve interaction with the command\-line client as well. .SH SEE ALSO .PP -\fBopenshift\-cli(1)\fP, \fBopenshift\-cli\-adm\-router(1)\fP, \fBopenshift\-cli\-adm\-ipfailover(1)\fP, \fBopenshift\-cli\-adm\-registry(1)\fP, \fBopenshift\-cli\-adm\-new\-project(1)\fP, \fBopenshift\-cli\-adm\-policy(1)\fP, \fBopenshift\-cli\-adm\-groups(1)\fP, \fBopenshift\-cli\-adm\-ca(1)\fP, \fBopenshift\-cli\-adm\-overwrite\-policy(1)\fP, \fBopenshift\-cli\-adm\-create\-node\-config(1)\fP, \fBopenshift\-cli\-adm\-manage\-node(1)\fP, \fBopenshift\-cli\-adm\-cordon(1)\fP, \fBopenshift\-cli\-adm\-uncordon(1)\fP, \fBopenshift\-cli\-adm\-drain(1)\fP, \fBopenshift\-cli\-adm\-taint(1)\fP, \fBopenshift\-cli\-adm\-pod\-network(1)\fP, \fBopenshift\-cli\-adm\-diagnostics(1)\fP, \fBopenshift\-cli\-adm\-prune(1)\fP, \fBopenshift\-cli\-adm\-build\-chain(1)\fP, \fBopenshift\-cli\-adm\-create\-kubeconfig(1)\fP, \fBopenshift\-cli\-adm\-create\-api\-client\-config(1)\fP, \fBopenshift\-cli\-adm\-create\-bootstrap\-project\-template(1)\fP, \fBopenshift\-cli\-adm\-create\-bootstrap\-policy\-file(1)\fP, \fBopenshift\-cli\-adm\-create\-login\-template(1)\fP, \fBopenshift\-cli\-adm\-create\-provider\-selection\-template(1)\fP, \fBopenshift\-cli\-adm\-create\-error\-template(1)\fP, \fBopenshift\-cli\-adm\-create\-master\-certs(1)\fP, \fBopenshift\-cli\-adm\-create\-key\-pair(1)\fP, \fBopenshift\-cli\-adm\-create\-server\-cert(1)\fP, \fBopenshift\-cli\-adm\-create\-signer\-cert(1)\fP, \fBopenshift\-cli\-adm\-config(1)\fP, \fBopenshift\-cli\-adm\-completion(1)\fP, \fBopenshift\-cli\-adm\-options(1)\fP, +\fBopenshift\-cli(1)\fP, \fBopenshift\-cli\-adm\-router(1)\fP, \fBopenshift\-cli\-adm\-ipfailover(1)\fP, \fBopenshift\-cli\-adm\-registry(1)\fP, \fBopenshift\-cli\-adm\-new\-project(1)\fP, \fBopenshift\-cli\-adm\-policy(1)\fP, \fBopenshift\-cli\-adm\-groups(1)\fP, \fBopenshift\-cli\-adm\-ca(1)\fP, \fBopenshift\-cli\-adm\-overwrite\-policy(1)\fP, \fBopenshift\-cli\-adm\-create\-node\-config(1)\fP, \fBopenshift\-cli\-adm\-manage\-node(1)\fP, \fBopenshift\-cli\-adm\-cordon(1)\fP, \fBopenshift\-cli\-adm\-uncordon(1)\fP, \fBopenshift\-cli\-adm\-drain(1)\fP, \fBopenshift\-cli\-adm\-taint(1)\fP, \fBopenshift\-cli\-adm\-pod\-network(1)\fP, \fBopenshift\-cli\-adm\-diagnostics(1)\fP, \fBopenshift\-cli\-adm\-prune(1)\fP, \fBopenshift\-cli\-adm\-build\-chain(1)\fP, \fBopenshift\-cli\-adm\-migrate(1)\fP, \fBopenshift\-cli\-adm\-create\-kubeconfig(1)\fP, \fBopenshift\-cli\-adm\-create\-api\-client\-config(1)\fP, \fBopenshift\-cli\-adm\-create\-bootstrap\-project\-template(1)\fP, \fBopenshift\-cli\-adm\-create\-bootstrap\-policy\-file(1)\fP, \fBopenshift\-cli\-adm\-create\-login\-template(1)\fP, \fBopenshift\-cli\-adm\-create\-provider\-selection\-template(1)\fP, \fBopenshift\-cli\-adm\-create\-error\-template(1)\fP, \fBopenshift\-cli\-adm\-create\-master\-certs(1)\fP, \fBopenshift\-cli\-adm\-create\-key\-pair(1)\fP, \fBopenshift\-cli\-adm\-create\-server\-cert(1)\fP, \fBopenshift\-cli\-adm\-create\-signer\-cert(1)\fP, \fBopenshift\-cli\-adm\-config(1)\fP, \fBopenshift\-cli\-adm\-completion(1)\fP, \fBopenshift\-cli\-adm\-options(1)\fP, .SH HISTORY diff --git a/pkg/cmd/admin/admin.go b/pkg/cmd/admin/admin.go index 1345046c6288..26c6d6c66495 100644 --- a/pkg/cmd/admin/admin.go +++ b/pkg/cmd/admin/admin.go @@ -11,6 +11,9 @@ import ( "github.com/openshift/origin/pkg/cmd/admin/cert" diagnostics "github.com/openshift/origin/pkg/cmd/admin/diagnostics" "github.com/openshift/origin/pkg/cmd/admin/groups" + "github.com/openshift/origin/pkg/cmd/admin/migrate" + migrateimages "github.com/openshift/origin/pkg/cmd/admin/migrate/images" + migratestorage "github.com/openshift/origin/pkg/cmd/admin/migrate/storage" "github.com/openshift/origin/pkg/cmd/admin/network" "github.com/openshift/origin/pkg/cmd/admin/node" "github.com/openshift/origin/pkg/cmd/admin/policy" @@ -33,7 +36,7 @@ Administrative Commands Commands for managing a cluster are exposed here. Many administrative actions involve interaction with the command-line client as well.` -func NewCommandAdmin(name, fullName string, out io.Writer, errout io.Writer) *cobra.Command { +func NewCommandAdmin(name, fullName string, in io.Reader, out io.Writer, errout io.Writer) *cobra.Command { // Main command cmds := &cobra.Command{ Use: name, @@ -81,6 +84,12 @@ func NewCommandAdmin(name, fullName string, out io.Writer, errout io.Writer) *co diagnostics.NewCmdDiagnostics(diagnostics.DiagnosticsRecommendedName, fullName+" "+diagnostics.DiagnosticsRecommendedName, out), prune.NewCommandPrune(prune.PruneRecommendedName, fullName+" "+prune.PruneRecommendedName, f, out), buildchain.NewCmdBuildChain(name, fullName+" "+buildchain.BuildChainRecommendedCommandName, f, out), + migrate.NewCommandMigrate( + migrate.MigrateRecommendedName, fullName+" "+migrate.MigrateRecommendedName, f, out, + // Migration commands + migrateimages.NewCmdMigrateImageReferences("image-references", fullName+" "+migrate.MigrateRecommendedName+" image-references", f, in, out, errout), + migratestorage.NewCmdMigrateAPIStorage("storage", fullName+" "+migrate.MigrateRecommendedName+" storage", f, in, out, errout), + ), }, }, { diff --git a/pkg/cmd/admin/migrate/images/imagerefs.go b/pkg/cmd/admin/migrate/images/imagerefs.go new file mode 100644 index 000000000000..3da24c87dd73 --- /dev/null +++ b/pkg/cmd/admin/migrate/images/imagerefs.go @@ -0,0 +1,468 @@ +package images + +import ( + "encoding/json" + "fmt" + "io" + "net/url" + "strings" + + "github.com/spf13/cobra" + + kapi "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/credentialprovider" + kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/runtime" + + buildapi "github.com/openshift/origin/pkg/build/api" + "github.com/openshift/origin/pkg/client" + "github.com/openshift/origin/pkg/cmd/admin/migrate" + "github.com/openshift/origin/pkg/cmd/util/clientcmd" + imageapi "github.com/openshift/origin/pkg/image/api" +) + +const ( + internalMigrateImagesLong = ` +Migrate references to Docker images + +This command updates embedded Docker image references on the server in place. By default it +will update image streams and images, and may be used to update resources with a pod template +(deployments, replication controllers, daemon sets). + +References are changed by providing a mapping between a source registry and name and the +desired registry and name. Either name or registry can be set to '*' to change all values. +The registry value "docker.io" is special and will handle any image reference that refers to +the DockerHub. You may pass multiple mappings - the first matching mapping will be applied +per resource. + +The following resource types may be migrated by this command: + +* images * daemonsets +* imagestreams * jobs +* buildconfigs * replicationcontrollers +* deploymentconfigs * pods +* secrets (docker) + +Only images, imagestreams, and secrets are updated by default. Updating images and image +streams requires administrative privileges.` + + internalMigrateImagesExample = ` # Perform a dry-run of migrating all "docker.io" references to "myregistry.com" + %[1]s docker.io/*=myregistry.com/* + + # To actually perform the migration, the confirm flag must be appended + %[1]s docker.io/*=myregistry.com/* --confirm + + # To see more details of what will be migrated, use the loglevel and output flags + %[1]s docker.io/*=myregistry.com/* --loglevel=2 -o yaml + + # Migrate from a service IP to an internal service DNS name + %[1]s 172.30.1.54/*=registry.openshift.svc.cluster.local/* + + # Migrate from a service IP to an internal service DNS name for all deployment configs and builds + %[1]s 172.30.1.54/*=registry.openshift.svc.cluster.local/* --include=buildconfigs,deploymentconfigs` +) + +type MigrateImageReferenceOptions struct { + migrate.ResourceOptions + + Client client.Interface + Mappings ImageReferenceMappings + UpdatePodSpecFn func(obj runtime.Object, fn func(*kapi.PodSpec) error) (bool, error) +} + +// NewCmdMigrateImageReferences implements a MigrateImages command +func NewCmdMigrateImageReferences(name, fullName string, f *clientcmd.Factory, in io.Reader, out, errout io.Writer) *cobra.Command { + options := &MigrateImageReferenceOptions{ + ResourceOptions: migrate.ResourceOptions{ + In: in, + Out: out, + ErrOut: errout, + Include: []string{"imagestream", "image", "secrets"}, + }, + } + cmd := &cobra.Command{ + Use: fmt.Sprintf("%s REGISTRY/NAME=REGISTRY/NAME [...]", name), + Short: "Update embedded Docker image references", + Long: internalMigrateImagesLong, + Example: fmt.Sprintf(internalMigrateImagesExample, fullName), + Run: func(cmd *cobra.Command, args []string) { + kcmdutil.CheckErr(options.Complete(f, cmd, args)) + kcmdutil.CheckErr(options.Validate()) + kcmdutil.CheckErr(options.Run()) + }, + } + options.ResourceOptions.Bind(cmd) + + return cmd +} + +func (o *MigrateImageReferenceOptions) Complete(f *clientcmd.Factory, c *cobra.Command, args []string) error { + var remainingArgs []string + for _, s := range args { + if !strings.Contains(s, "=") { + remainingArgs = append(remainingArgs, s) + continue + } + mapping, err := ParseMapping(s) + if err != nil { + return err + } + o.Mappings = append(o.Mappings, mapping) + } + + o.UpdatePodSpecFn = f.UpdatePodSpecForObject + + if len(remainingArgs) > 0 { + return fmt.Errorf("all arguments must be valid FROM=TO mappings") + } + + o.ResourceOptions.SaveFn = o.save + if err := o.ResourceOptions.Complete(f, c); err != nil { + return err + } + + osclient, _, err := f.Clients() + if err != nil { + return err + } + o.Client = osclient + + return nil +} + +func (o MigrateImageReferenceOptions) Validate() error { + if len(o.Mappings) == 0 { + return fmt.Errorf("at least one mapping argument must be specified: REGISTRY/NAME=REGISTRY/NAME") + } + return o.ResourceOptions.Validate() +} + +func (o MigrateImageReferenceOptions) Run() error { + return o.ResourceOptions.Visitor().Visit(func(info *resource.Info) (migrate.Reporter, error) { + return o.transform(info.Object) + }) +} + +// save invokes the API to alter an object. The reporter passed to this method is the same returned by +// the migration visitor method (for this type, transformImageReferences). It should return an error +// if the input type cannot be saved. It returns migrate.ErrRecalculate if migration should be re-run +// on the provided object. +func (o *MigrateImageReferenceOptions) save(info *resource.Info, reporter migrate.Reporter) error { + switch t := info.Object.(type) { + case *imageapi.ImageStream: + // update status first so that a subsequent spec update won't pull incorrect values + if reporter.(imageChangeInfo).status { + updated, err := o.Client.ImageStreams(t.Namespace).UpdateStatus(t) + if err != nil { + return migrate.DefaultRetriable(info, err) + } + info.Refresh(updated, true) + return migrate.ErrRecalculate + } + if reporter.(imageChangeInfo).spec { + updated, err := o.Client.ImageStreams(t.Namespace).Update(t) + if err != nil { + return migrate.DefaultRetriable(info, err) + } + info.Refresh(updated, true) + } + return nil + default: + if _, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, info.Object); err != nil { + return migrate.DefaultRetriable(info, err) + } + } + return nil +} + +// transform checks image references on the provided object and returns either a reporter (indicating +// that the object was recognized and whether it was updated) or an error. +func (o *MigrateImageReferenceOptions) transform(obj runtime.Object) (migrate.Reporter, error) { + fn := o.Mappings.MapReference + switch t := obj.(type) { + case *imageapi.Image: + var changed bool + if updated := fn(t.DockerImageReference); updated != t.DockerImageReference { + changed = true + t.DockerImageReference = updated + } + return reporter(changed), nil + case *imageapi.ImageStream: + var info imageChangeInfo + if len(t.Spec.DockerImageRepository) > 0 { + info.spec = updateString(&t.Spec.DockerImageRepository, fn) + } + for _, ref := range t.Spec.Tags { + if ref.From == nil || ref.From.Kind != "DockerImage" { + continue + } + info.spec = updateString(&ref.From.Name, fn) || info.spec + } + for _, events := range t.Status.Tags { + for i := range events.Items { + info.status = updateString(&events.Items[i].DockerImageReference, fn) || info.status + } + } + return info, nil + case *kapi.Secret: + switch t.Type { + case kapi.SecretTypeDockercfg: + var v credentialprovider.DockerConfig + if err := json.Unmarshal(t.Data[kapi.DockerConfigKey], &v); err != nil { + return nil, err + } + if !updateDockerConfig(v, o.Mappings.MapDockerAuthKey) { + return reporter(false), nil + } + data, err := json.Marshal(v) + if err != nil { + return nil, err + } + t.Data[kapi.DockerConfigKey] = data + return reporter(true), nil + case kapi.SecretTypeDockerConfigJson: + var v credentialprovider.DockerConfigJson + if err := json.Unmarshal(t.Data[kapi.DockerConfigJsonKey], &v); err != nil { + return nil, err + } + if !updateDockerConfig(v.Auths, o.Mappings.MapDockerAuthKey) { + return reporter(false), nil + } + data, err := json.Marshal(v) + if err != nil { + return nil, err + } + t.Data[kapi.DockerConfigJsonKey] = data + return reporter(true), nil + default: + return reporter(false), nil + } + case *buildapi.BuildConfig: + var changed bool + if to := t.Spec.Output.To; to != nil && to.Kind == "DockerImage" { + changed = updateString(&to.Name, fn) || changed + } + for i, image := range t.Spec.Source.Images { + if image.From.Kind == "DockerImage" { + changed = updateString(&t.Spec.Source.Images[i].From.Name, fn) || changed + } + } + if c := t.Spec.Strategy.CustomStrategy; c != nil && c.From.Kind == "DockerImage" { + changed = updateString(&c.From.Name, fn) || changed + } + if c := t.Spec.Strategy.DockerStrategy; c != nil && c.From.Kind == "DockerImage" { + changed = updateString(&c.From.Name, fn) || changed + } + if c := t.Spec.Strategy.SourceStrategy; c != nil && c.From.Kind == "DockerImage" { + changed = updateString(&c.From.Name, fn) || changed + } + return reporter(changed), nil + default: + if o.UpdatePodSpecFn != nil { + var changed bool + supports, err := o.UpdatePodSpecFn(obj, func(spec *kapi.PodSpec) error { + changed = updatePodSpec(spec, fn) + return nil + }) + if !supports { + return nil, nil + } + if err != nil { + return nil, err + } + return reporter(changed), nil + } + } + // TODO: implement use of the generic PodTemplate accessor from the factory to handle + // any object with a pod template + return nil, nil +} + +// reporter implements the Reporter interface for a boolean. +type reporter bool + +func (r reporter) Changed() bool { + return bool(r) +} + +// imageChangeInfo indicates whether the spec or status of an image stream was changed. +type imageChangeInfo struct { + spec, status bool +} + +func (i imageChangeInfo) Changed() bool { + return i.spec || i.status +} + +type TransformImageFunc func(in string) string + +func updateString(value *string, fn TransformImageFunc) bool { + result := fn(*value) + if result != *value { + *value = result + return true + } + return false +} + +func updatePodSpec(spec *kapi.PodSpec, fn TransformImageFunc) bool { + var changed bool + for i := range spec.Containers { + changed = updateString(&spec.Containers[i].Image, fn) || changed + } + return changed +} + +func updateDockerConfig(cfg credentialprovider.DockerConfig, fn TransformImageFunc) bool { + var changed bool + for k, v := range cfg { + original := k + if updateString(&k, fn) { + changed = true + delete(cfg, original) + cfg[k] = v + } + } + return changed +} + +// ImageReferenceMapping represents a transformation of an image reference. +type ImageReferenceMapping struct { + FromRegistry string + FromName string + ToRegistry string + ToName string +} + +// ParseMapping converts a string in the form "(REGISTRY|*)/(NAME|*)" to an ImageReferenceMapping +// or returns a user-facing error. REGISTRY is the image registry value (hostname) or "docker.io". +// NAME is the full repository name (the path relative to the registry root). +// TODO: handle v2 repository names, which can have multiple segments (must fix +// ParseDockerImageReference) +func ParseMapping(s string) (ImageReferenceMapping, error) { + parts := strings.SplitN(s, "=", 2) + from := strings.SplitN(parts[0], "/", 2) + to := strings.SplitN(parts[1], "/", 2) + if len(from) < 2 || len(to) < 2 { + return ImageReferenceMapping{}, fmt.Errorf("all arguments must be of the form REGISTRY/NAME=REGISTRY/NAME, where registry or name may be '*' or a value") + } + if len(from[0]) == 0 { + return ImageReferenceMapping{}, fmt.Errorf("%q is not a valid source: registry must be specified (may be '*')", parts[0]) + } + if len(from[1]) == 0 { + return ImageReferenceMapping{}, fmt.Errorf("%q is not a valid source: name must be specified (may be '*')", parts[0]) + } + if len(to[0]) == 0 { + return ImageReferenceMapping{}, fmt.Errorf("%q is not a valid target: registry must be specified (may be '*')", parts[1]) + } + if len(to[1]) == 0 { + return ImageReferenceMapping{}, fmt.Errorf("%q is not a valid target: name must be specified (may be '*')", parts[1]) + } + if from[0] == "*" { + from[0] = "" + } + if from[1] == "*" { + from[1] = "" + } + if to[0] == "*" { + to[0] = "" + } + if to[1] == "*" { + to[1] = "" + } + if to[0] == "" && to[1] == "" { + return ImageReferenceMapping{}, fmt.Errorf("%q is not a valid target: at least one change must be specified", parts[1]) + } + if from[0] == to[0] && from[1] == to[1] { + return ImageReferenceMapping{}, fmt.Errorf("%q is not valid: must target at least one field to change", s) + } + return ImageReferenceMapping{ + FromRegistry: from[0], + FromName: from[1], + ToRegistry: to[0], + ToName: to[1], + }, nil +} + +// ImageReferenceMappings provide a convenience method for transforming an input reference +type ImageReferenceMappings []ImageReferenceMapping + +// MapReference transforms the provided Docker image reference if any mapping matches the +// input. If the reference cannot be parsed, it will not be modified. +func (m ImageReferenceMappings) MapReference(in string) string { + ref, err := imageapi.ParseDockerImageReference(in) + if err != nil { + return in + } + registry := ref.DockerClientDefaults().Registry + name := ref.RepositoryName() + for _, mapping := range m { + if len(mapping.FromRegistry) > 0 && mapping.FromRegistry != registry { + continue + } + if len(mapping.FromName) > 0 && mapping.FromName != name { + continue + } + if len(mapping.ToRegistry) > 0 { + ref.Registry = mapping.ToRegistry + } + if len(mapping.ToName) > 0 { + ref.Namespace = "" + ref.Name = mapping.ToName + } + return ref.Exact() + } + return in +} + +// MapDockerAuthKey transforms the provided Docker Config host key if any mapping matches +// the input. If the reference cannot be parsed, it will not be modified. +func (m ImageReferenceMappings) MapDockerAuthKey(in string) string { + value := in + if len(value) == 0 { + value = imageapi.DockerDefaultV1Registry + } + if !strings.HasPrefix(value, "https://") && !strings.HasPrefix(value, "http://") { + value = "https://" + value + } + parsed, err := url.Parse(value) + if err != nil { + return in + } + // The docker client allows exact matches: + // foo.bar.com/namespace + // Or hostname matches: + // foo.bar.com + // It also considers /v2/ and /v1/ equivalent to the hostname + // See ResolveAuthConfig in docker/registry/auth.go. + registry := parsed.Host + name := parsed.Path + switch { + case name == "/": + name = "" + case strings.HasPrefix(name, "/v2/") || strings.HasPrefix(name, "/v1/"): + name = name[4:] + case strings.HasPrefix(name, "/"): + name = name[1:] + } + for _, mapping := range m { + if len(mapping.FromRegistry) > 0 && mapping.FromRegistry != registry { + continue + } + if len(mapping.FromName) > 0 && mapping.FromName != name { + continue + } + if len(mapping.ToRegistry) > 0 { + registry = mapping.ToRegistry + } + if len(mapping.ToName) > 0 { + name = mapping.ToName + } + if len(name) > 0 { + return registry + "/" + name + } + return registry + } + return in +} diff --git a/pkg/cmd/admin/migrate/images/imagerefs_test.go b/pkg/cmd/admin/migrate/images/imagerefs_test.go new file mode 100644 index 000000000000..e36672125a6a --- /dev/null +++ b/pkg/cmd/admin/migrate/images/imagerefs_test.go @@ -0,0 +1,601 @@ +package images + +import ( + "testing" + + kapi "k8s.io/kubernetes/pkg/api" + kbatch "k8s.io/kubernetes/pkg/apis/batch" + kextensions "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/util/diff" + + buildapi "github.com/openshift/origin/pkg/build/api" + "github.com/openshift/origin/pkg/cmd/util/clientcmd" + deployapi "github.com/openshift/origin/pkg/deploy/api" + imageapi "github.com/openshift/origin/pkg/image/api" +) + +func TestImageReferenceMappingsMapReference(t *testing.T) { + testCases := []struct { + mappings ImageReferenceMappings + results map[string]string + }{ + { + mappings: ImageReferenceMappings{{FromRegistry: "docker.io", ToRegistry: "index.docker.io"}}, + results: map[string]string{ + "mysql": "index.docker.io/mysql", + "mysql:latest": "index.docker.io/mysql:latest", + "default/mysql:latest": "index.docker.io/default/mysql:latest", + + "mysql@sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237": "index.docker.io/mysql@sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237", + + "docker.io/mysql": "index.docker.io/library/mysql", + "docker.io/mysql:latest": "index.docker.io/library/mysql:latest", + "docker.io/default/mysql:latest": "index.docker.io/default/mysql:latest", + + "docker.io/mysql@sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237": "index.docker.io/library/mysql@sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237", + }, + }, + { + mappings: ImageReferenceMappings{{FromName: "test/other", ToRegistry: "another.registry"}}, + results: map[string]string{ + "test/other": "another.registry/test/other", + "test/other:latest": "another.registry/test/other:latest", + "myregistry.com/test/other:latest": "another.registry/test/other:latest", + + "myregistry.com/b/test/other:latest": "myregistry.com/b/test/other:latest", + }, + }, + { + mappings: ImageReferenceMappings{{FromName: "test/other", ToName: "other/test"}}, + results: map[string]string{ + "test/other": "other/test", + "test/other:latest": "other/test:latest", + "myregistry.com/test/other:latest": "myregistry.com/other/test:latest", + + "test/other/b:latest": "test/other/b:latest", + + // TODO: this is possibly wrong with V2 and latest daemon + "b/test/other:latest": "b/other/test:latest", + }, + }, + } + + for i, test := range testCases { + for in, out := range test.results { + result := test.mappings.MapReference(in) + if result != out { + t.Errorf("%d: expect %s -> %s, got %q", i, in, out, result) + continue + } + } + } +} + +func TestImageReferenceMappingsMapDockerAuthKey(t *testing.T) { + testCases := []struct { + mappings ImageReferenceMappings + results map[string]string + }{ + { + mappings: ImageReferenceMappings{{FromRegistry: "docker.io", ToRegistry: "index.docker.io"}}, + results: map[string]string{ + "docker.io": "index.docker.io", + "index.docker.io": "index.docker.io", + "https://index.docker.io/v1/": "https://index.docker.io/v1/", + "https://docker.io/v1/": "index.docker.io", + + "other.docker.io": "other.docker.io", + "other.docker.io/names": "other.docker.io/names", + "other.docker.io:5000/names": "other.docker.io:5000/names", + "https://other.docker.io/v1/": "https://other.docker.io/v1/", + }, + }, + { + mappings: ImageReferenceMappings{{FromRegistry: "index.docker.io", ToRegistry: "another.registry"}}, + results: map[string]string{ + "index.docker.io": "another.registry", + "index.docker.io/other": "another.registry/other", + "https://index.docker.io/v1/other": "another.registry/other", + "https://index.docker.io/v1/": "another.registry", + "https://index.docker.io/": "another.registry", + "https://index.docker.io": "another.registry", + + "docker.io": "docker.io", + "https://docker.io/v1/": "https://docker.io/v1/", + "other.docker.io": "other.docker.io", + "other.docker.io/names": "other.docker.io/names", + "other.docker.io:5000/names": "other.docker.io:5000/names", + "https://other.docker.io/v1/": "https://other.docker.io/v1/", + }, + }, + { + mappings: ImageReferenceMappings{{FromRegistry: "index.docker.io", ToRegistry: "another.registry", ToName: "extra"}}, + results: map[string]string{ + "index.docker.io": "another.registry/extra", + "index.docker.io/other": "another.registry/extra", + "https://index.docker.io/v1/other": "another.registry/extra", + "https://index.docker.io/v1/": "another.registry/extra", + "https://index.docker.io/": "another.registry/extra", + + "docker.io": "docker.io", + "https://docker.io/v1/": "https://docker.io/v1/", + "other.docker.io": "other.docker.io", + "other.docker.io/names": "other.docker.io/names", + "other.docker.io:5000/names": "other.docker.io:5000/names", + "https://other.docker.io/v1/": "https://other.docker.io/v1/", + }, + }, + } + + for i, test := range testCases { + for in, out := range test.results { + result := test.mappings.MapDockerAuthKey(in) + if result != out { + t.Errorf("%d: expect %s -> %s, got %q", i, in, out, result) + continue + } + } + } +} + +func TestTransform(t *testing.T) { + type variant struct { + changed bool + nilReporter bool + err bool + obj, expected runtime.Object + } + testCases := []struct { + mappings ImageReferenceMappings + variants []variant + }{ + { + mappings: ImageReferenceMappings{{FromRegistry: "docker.io", ToRegistry: "index.docker.io"}}, + variants: []variant{ + { + obj: &kapi.Pod{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "docker.io/foo/bar"}, + {Image: "foo/bar"}, + }, + }, + }, + changed: true, + expected: &kapi.Pod{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "index.docker.io/foo/bar"}, + {Image: "index.docker.io/foo/bar"}, + }, + }, + }, + }, + { + obj: &kapi.ReplicationController{ + Spec: kapi.ReplicationControllerSpec{ + Template: &kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "docker.io/foo/bar"}, + {Image: "foo/bar"}, + }, + }, + }, + }, + }, + changed: true, + expected: &kapi.ReplicationController{ + Spec: kapi.ReplicationControllerSpec{ + Template: &kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "index.docker.io/foo/bar"}, + {Image: "index.docker.io/foo/bar"}, + }, + }, + }, + }, + }, + }, + { + obj: &kextensions.Deployment{ + Spec: kextensions.DeploymentSpec{ + Template: kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "docker.io/foo/bar"}, + {Image: "foo/bar"}, + }, + }, + }, + }, + }, + changed: true, + expected: &kextensions.Deployment{ + Spec: kextensions.DeploymentSpec{ + Template: kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "index.docker.io/foo/bar"}, + {Image: "index.docker.io/foo/bar"}, + }, + }, + }, + }, + }, + }, + { + obj: &deployapi.DeploymentConfig{ + Spec: deployapi.DeploymentConfigSpec{ + Template: &kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "docker.io/foo/bar"}, + {Image: "foo/bar"}, + }, + }, + }, + }, + }, + changed: true, + expected: &deployapi.DeploymentConfig{ + Spec: deployapi.DeploymentConfigSpec{ + Template: &kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "index.docker.io/foo/bar"}, + {Image: "index.docker.io/foo/bar"}, + }, + }, + }, + }, + }, + }, + { + obj: &kextensions.DaemonSet{ + Spec: kextensions.DaemonSetSpec{ + Template: kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "docker.io/foo/bar"}, + {Image: "foo/bar"}, + }, + }, + }, + }, + }, + changed: true, + expected: &kextensions.DaemonSet{ + Spec: kextensions.DaemonSetSpec{ + Template: kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "index.docker.io/foo/bar"}, + {Image: "index.docker.io/foo/bar"}, + }, + }, + }, + }, + }, + }, + { + obj: &kextensions.ReplicaSet{ + Spec: kextensions.ReplicaSetSpec{ + Template: kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "docker.io/foo/bar"}, + {Image: "foo/bar"}, + }, + }, + }, + }, + }, + changed: true, + expected: &kextensions.ReplicaSet{ + Spec: kextensions.ReplicaSetSpec{ + Template: kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "index.docker.io/foo/bar"}, + {Image: "index.docker.io/foo/bar"}, + }, + }, + }, + }, + }, + }, + { + obj: &kbatch.Job{ + Spec: kbatch.JobSpec{ + Template: kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "docker.io/foo/bar"}, + {Image: "foo/bar"}, + }, + }, + }, + }, + }, + changed: true, + expected: &kbatch.Job{ + Spec: kbatch.JobSpec{ + Template: kapi.PodTemplateSpec{ + Spec: kapi.PodSpec{ + Containers: []kapi.Container{ + {Image: "index.docker.io/foo/bar"}, + {Image: "index.docker.io/foo/bar"}, + }, + }, + }, + }, + }, + }, + { + obj: &kapi.Node{}, + nilReporter: true, + }, + { + obj: &buildapi.BuildConfig{ + Spec: buildapi.BuildConfigSpec{ + CommonSpec: buildapi.CommonSpec{ + Output: buildapi.BuildOutput{To: &kapi.ObjectReference{Kind: "DockerImage", Name: "docker.io/foo/bar"}}, + Source: buildapi.BuildSource{ + Images: []buildapi.ImageSource{ + {From: kapi.ObjectReference{Kind: "DockerImage", Name: "docker.io/foo/bar"}}, + {From: kapi.ObjectReference{Kind: "DockerImage", Name: "foo/bar"}}, + }, + }, + Strategy: buildapi.BuildStrategy{ + DockerStrategy: &buildapi.DockerBuildStrategy{From: &kapi.ObjectReference{Kind: "DockerImage", Name: "docker.io/foo/bar"}}, + SourceStrategy: &buildapi.SourceBuildStrategy{From: kapi.ObjectReference{Kind: "DockerImage", Name: "docker.io/foo/bar"}}, + CustomStrategy: &buildapi.CustomBuildStrategy{From: kapi.ObjectReference{Kind: "DockerImage", Name: "docker.io/foo/bar"}}, + }, + }, + }, + }, + changed: true, + expected: &buildapi.BuildConfig{ + Spec: buildapi.BuildConfigSpec{ + CommonSpec: buildapi.CommonSpec{ + Output: buildapi.BuildOutput{To: &kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/foo/bar"}}, + Source: buildapi.BuildSource{ + Images: []buildapi.ImageSource{ + {From: kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/foo/bar"}}, + {From: kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/foo/bar"}}, + }, + }, + Strategy: buildapi.BuildStrategy{ + DockerStrategy: &buildapi.DockerBuildStrategy{From: &kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/foo/bar"}}, + SourceStrategy: &buildapi.SourceBuildStrategy{From: kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/foo/bar"}}, + CustomStrategy: &buildapi.CustomBuildStrategy{From: kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/foo/bar"}}, + }, + }, + }, + }, + }, + { + obj: &kapi.Secret{ + Type: kapi.SecretTypeDockercfg, + Data: map[string][]byte{ + kapi.DockerConfigKey: []byte(`{"docker.io":{"auth":"Og=="},"other.server":{"auth":"Og=="}}`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + changed: true, + expected: &kapi.Secret{ + Type: kapi.SecretTypeDockercfg, + Data: map[string][]byte{ + kapi.DockerConfigKey: []byte(`{"index.docker.io":{"auth":"Og=="},"other.server":{"auth":"Og=="}}`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + }, + { + obj: &kapi.Secret{ + Type: kapi.SecretTypeDockercfg, + Data: map[string][]byte{ + kapi.DockerConfigKey: []byte(`{"myserver.com":{"auth":"Og=="},"other.server":{"auth":"Og=="}}`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + expected: &kapi.Secret{ + Type: kapi.SecretTypeDockercfg, + Data: map[string][]byte{ + kapi.DockerConfigKey: []byte(`{"myserver.com":{"auth":"Og=="},"other.server":{"auth":"Og=="}}`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + }, + { + obj: &kapi.Secret{ + Type: kapi.SecretTypeDockerConfigJson, + Data: map[string][]byte{ + kapi.DockerConfigJsonKey: []byte(`{"auths":{"docker.io":{"auth":"Og=="},"other.server":{"auth":"Og=="}}}`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + changed: true, + expected: &kapi.Secret{ + Type: kapi.SecretTypeDockerConfigJson, + Data: map[string][]byte{ + kapi.DockerConfigJsonKey: []byte(`{"auths":{"index.docker.io":{"auth":"Og=="},"other.server":{"auth":"Og=="}}}`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + }, + { + obj: &kapi.Secret{ + Type: kapi.SecretTypeDockerConfigJson, + Data: map[string][]byte{ + kapi.DockerConfigJsonKey: []byte(`{"auths":{"myserver.com":{},"other.server":{}}}`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + expected: &kapi.Secret{ + Type: kapi.SecretTypeDockerConfigJson, + Data: map[string][]byte{ + kapi.DockerConfigJsonKey: []byte(`{"auths":{"myserver.com":{},"other.server":{}}}`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + }, + { + obj: &kapi.Secret{ + Type: kapi.SecretTypeDockercfg, + Data: map[string][]byte{ + kapi.DockerConfigKey: []byte(`{"auths":{`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + err: true, + expected: &kapi.Secret{ + Type: kapi.SecretTypeDockercfg, + Data: map[string][]byte{ + kapi.DockerConfigKey: []byte(`{"auths":{`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + }, + { + obj: &kapi.Secret{ + Type: kapi.SecretTypeDockerConfigJson, + Data: map[string][]byte{ + kapi.DockerConfigJsonKey: []byte(`{"auths":{`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + err: true, + expected: &kapi.Secret{ + Type: kapi.SecretTypeDockerConfigJson, + Data: map[string][]byte{ + kapi.DockerConfigJsonKey: []byte(`{"auths":{`), + "another": []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + }, + { + obj: &kapi.Secret{ + Type: kapi.SecretTypeOpaque, + Data: map[string][]byte{ + kapi.DockerConfigJsonKey: []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + expected: &kapi.Secret{ + Type: kapi.SecretTypeOpaque, + Data: map[string][]byte{ + kapi.DockerConfigJsonKey: []byte(`{"auths":{"docker.io":{},"other.server":{}}}`), + }, + }, + }, + { + obj: &imageapi.Image{ + DockerImageReference: "docker.io/foo/bar", + }, + changed: true, + expected: &imageapi.Image{ + DockerImageReference: "index.docker.io/foo/bar", + }, + }, + { + obj: &imageapi.Image{ + DockerImageReference: "other.docker.io/foo/bar", + }, + expected: &imageapi.Image{ + DockerImageReference: "other.docker.io/foo/bar", + }, + }, + { + obj: &imageapi.ImageStream{ + Spec: imageapi.ImageStreamSpec{ + Tags: map[string]imageapi.TagReference{ + "foo": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "docker.io/foo/bar"}}, + "bar": {From: &kapi.ObjectReference{Kind: "ImageStream", Name: "docker.io/foo/bar"}}, + "baz": {}, + }, + DockerImageRepository: "docker.io/foo/bar", + }, + Status: imageapi.ImageStreamStatus{ + DockerImageRepository: "docker.io/foo/bar", + Tags: map[string]imageapi.TagEventList{ + "bar": {Items: []imageapi.TagEvent{ + {DockerImageReference: "docker.io/foo/bar"}, + {DockerImageReference: "docker.io/foo/bar"}, + }}, + "baz": {Items: []imageapi.TagEvent{ + {DockerImageReference: "some.other/reference"}, + {DockerImageReference: "docker.io/foo/bar"}, + }}, + }, + }, + }, + changed: true, + expected: &imageapi.ImageStream{ + Spec: imageapi.ImageStreamSpec{ + Tags: map[string]imageapi.TagReference{ + "foo": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/foo/bar"}}, + "bar": {From: &kapi.ObjectReference{Kind: "ImageStream", Name: "docker.io/foo/bar"}}, + "baz": {}, + }, + DockerImageRepository: "index.docker.io/foo/bar", + }, + Status: imageapi.ImageStreamStatus{ + DockerImageRepository: "docker.io/foo/bar", + Tags: map[string]imageapi.TagEventList{ + "bar": {Items: []imageapi.TagEvent{ + {DockerImageReference: "index.docker.io/foo/bar"}, + {DockerImageReference: "index.docker.io/foo/bar"}, + }}, + "baz": {Items: []imageapi.TagEvent{ + {DockerImageReference: "some.other/reference"}, + {DockerImageReference: "index.docker.io/foo/bar"}, + }}, + }, + }, + }, + }, + }, + }, + { + mappings: ImageReferenceMappings{{FromRegistry: "index.docker.io", ToRegistry: "another.registry"}}, + }, + { + mappings: ImageReferenceMappings{{FromRegistry: "index.docker.io", ToRegistry: "another.registry", ToName: "extra"}}, + }, + } + + for _, test := range testCases { + for i, v := range test.variants { + o := MigrateImageReferenceOptions{ + Mappings: test.mappings, + UpdatePodSpecFn: clientcmd.NewFactory(nil).UpdatePodSpecForObject, + } + reporter, err := o.transform(v.obj) + if (err != nil) != v.err { + t.Errorf("%d: %v %t", i, err, v.err) + continue + } + if err != nil { + continue + } + if (reporter == nil) != v.nilReporter { + t.Errorf("%d: reporter %#v %t", i, reporter, v.nilReporter) + continue + } + if reporter == nil { + continue + } + if reporter.Changed() != v.changed { + t.Errorf("%d: changed %#v %t", i, reporter, v.changed) + continue + } + if !kapi.Semantic.DeepEqual(v.expected, v.obj) { + t.Errorf("%d: object: %s", i, diff.ObjectDiff(v.expected, v.obj)) + continue + } + } + } +} diff --git a/pkg/cmd/admin/migrate/migrate.go b/pkg/cmd/admin/migrate/migrate.go new file mode 100644 index 000000000000..aadb49ba4ded --- /dev/null +++ b/pkg/cmd/admin/migrate/migrate.go @@ -0,0 +1,28 @@ +package migrate + +import ( + "io" + + "github.com/spf13/cobra" + + cmdutil "github.com/openshift/origin/pkg/cmd/util" + "github.com/openshift/origin/pkg/cmd/util/clientcmd" +) + +const MigrateRecommendedName = "migrate" + +const migrateLong = `Migrate resources on the cluster + +These commands assist administrators in performing preventative maintenance on a cluster.` + +func NewCommandMigrate(name, fullName string, f *clientcmd.Factory, out io.Writer, cmds ...*cobra.Command) *cobra.Command { + // Parent command to which all subcommands are added. + cmd := &cobra.Command{ + Use: name, + Short: "Migrate data in the cluster", + Long: migrateLong, + Run: cmdutil.DefaultSubCommandRun(out), + } + cmd.AddCommand(cmds...) + return cmd +} diff --git a/pkg/cmd/admin/migrate/migrator.go b/pkg/cmd/admin/migrate/migrator.go new file mode 100644 index 000000000000..7457da195fc1 --- /dev/null +++ b/pkg/cmd/admin/migrate/migrator.go @@ -0,0 +1,479 @@ +package migrate + +import ( + "fmt" + "io" + "strings" + + "github.com/golang/glog" + "github.com/spf13/cobra" + + "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/api/meta" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/kubectl" + "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/util/sets" + + cmdutil "github.com/openshift/origin/pkg/cmd/util" + "github.com/openshift/origin/pkg/cmd/util/clientcmd" +) + +// MigrateVisitFunc is invoked for each returned object, and may return a +// Reporter that can contain info to be used by save. +type MigrateVisitFunc func(info *resource.Info) (Reporter, error) + +// MigrateActionFunc is expected to persist the altered info.Object. The +// Reporter returned from Visit is passed to this function and may be used +// to carry additional information about what to save on an object. +type MigrateActionFunc func(info *resource.Info, reporter Reporter) error + +// MigrateFilterFunc can return false to skip an item, or an error. +type MigrateFilterFunc func(info *resource.Info) (bool, error) + +// Reporter indicates whether a resource requires migration. +type Reporter interface { + // Changed returns true if the resource requires migration. + Changed() bool +} + +// ResourceOptions assists in performing migrations on any object that +// can be retrieved via the API. +type ResourceOptions struct { + In io.Reader + Out, ErrOut io.Writer + + AllNamespaces bool + Include []string + Filenames []string + Confirm bool + Output string + FromKey string + ToKey string + + OverlappingResources []sets.String + DefaultExcludes []unversioned.GroupResource + + Builder *resource.Builder + SaveFn MigrateActionFunc + PrintFn MigrateActionFunc + FilterFn MigrateFilterFunc + DryRun bool + Summarize bool +} + +func (o *ResourceOptions) Bind(c *cobra.Command) { + c.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output the modified objects instead of saving them, valid values are 'yaml' or 'json'") + c.Flags().StringSliceVar(&o.Include, "include", o.Include, "Resource types to migrate. Passing --filename will override this flag.") + c.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", true, "Migrate objects in all namespaces. Defaults to true.") + c.Flags().BoolVar(&o.Confirm, "confirm", false, "If true, all requested objects will be migrated. Defaults to false.") + + c.Flags().StringVar(&o.FromKey, "from-key", o.FromKey, "If specified, only migrate items with a key (namespace/name or name) greater than or equal to this value") + c.Flags().StringVar(&o.ToKey, "to-key", o.ToKey, "If specified, only migrate items with a key (namespace/name or name) less than this value") + + usage := "Filename, directory, or URL to docker-compose.yml file to use" + kubectl.AddJsonFilenameFlag(c, &o.Filenames, usage) + c.MarkFlagRequired("filename") +} + +func (o *ResourceOptions) Complete(f *clientcmd.Factory, c *cobra.Command) error { + switch { + case len(o.Output) > 0: + printer, _, err := kubectl.GetPrinter(o.Output, "") + if err != nil { + return err + } + first := true + o.PrintFn = func(info *resource.Info, _ Reporter) error { + obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion()) + if err != nil { + return err + } + // TODO: PrintObj is not correct for YAML - it should inject document separators itself + if o.Output == "yaml" && !first { + fmt.Fprintln(o.Out, "---") + } + first = false + printer.PrintObj(obj, o.Out) + return nil + } + o.DryRun = true + case o.Confirm: + o.DryRun = false + default: + o.DryRun = true + } + + namespace, explicitNamespace, err := f.Factory.DefaultNamespace() + if err != nil { + return err + } + allNamespaces := !explicitNamespace && o.AllNamespaces + + if len(o.FromKey) > 0 || len(o.ToKey) > 0 { + o.FilterFn = func(info *resource.Info) (bool, error) { + var key string + if info.Mapping.Scope.Name() == meta.RESTScopeNameNamespace { + key = info.Namespace + "/" + info.Name + } else { + if !allNamespaces { + return false, nil + } + key = info.Name + } + if len(o.FromKey) > 0 && o.FromKey > key { + return false, nil + } + if len(o.ToKey) > 0 && o.ToKey <= key { + return false, nil + } + return true, nil + } + } + + oclient, _, err := f.Clients() + if err != nil { + return err + } + mapper, _ := f.Object(false) + + resourceNames := sets.NewString() + for i, s := range o.Include { + if resourceNames.Has(s) { + continue + } + if s != "*" { + resourceNames.Insert(s) + break + } + + all, err := clientcmd.FindAllCanonicalResources(oclient.Discovery(), mapper) + if err != nil { + return fmt.Errorf("could not calculate the list of available resources: %v", err) + } + exclude := sets.NewString() + for _, gr := range o.DefaultExcludes { + exclude.Insert(gr.String()) + } + candidate := sets.NewString() + for _, gr := range all { + // if the user specifies a resource that matches resource or resource+group, skip it + if resourceNames.Has(gr.Resource) || resourceNames.Has(gr.String()) || exclude.Has(gr.String()) { + continue + } + candidate.Insert(gr.String()) + } + candidate.Delete(exclude.List()...) + include := candidate + if len(o.OverlappingResources) > 0 { + include = sets.NewString() + for _, k := range candidate.List() { + reduce := k + for _, others := range o.OverlappingResources { + if !others.Has(k) { + continue + } + reduce = others.List()[0] + break + } + include.Insert(reduce) + } + } + glog.V(4).Infof("Found the following resources from the server: %v", include.List()) + last := o.Include[i+1:] + o.Include = append([]string{}, o.Include[:i]...) + o.Include = append(o.Include, include.List()...) + o.Include = append(o.Include, last...) + break + } + + o.Builder = f.Factory.NewBuilder(false). + AllNamespaces(allNamespaces). + FilenameParam(false, false, o.Filenames...). + ContinueOnError(). + DefaultNamespace(). + RequireObject(true). + SelectAllParam(true). + Flatten() + if !allNamespaces { + o.Builder.NamespaceParam(namespace) + } + if len(o.Filenames) == 0 { + o.Builder.ResourceTypes(o.Include...) + } + return nil +} + +func (o *ResourceOptions) Validate() error { + if len(o.Filenames) == 0 && len(o.Include) == 0 { + return fmt.Errorf("you must specify at least one resource or resource type to migrate with --include or --filenames") + } + return nil +} + +func (o *ResourceOptions) Visitor() *ResourceVisitor { + return &ResourceVisitor{ + Out: o.Out, + Builder: o.Builder, + SaveFn: o.SaveFn, + PrintFn: o.PrintFn, + FilterFn: o.FilterFn, + DryRun: o.DryRun, + } +} + +type ResourceVisitor struct { + Out io.Writer + + Builder *resource.Builder + + SaveFn MigrateActionFunc + PrintFn MigrateActionFunc + FilterFn MigrateFilterFunc + + DryRun bool +} + +func (o *ResourceVisitor) Visit(fn MigrateVisitFunc) error { + dryRun := o.DryRun + summarize := true + actionFn := o.SaveFn + switch { + case o.PrintFn != nil: + actionFn = o.PrintFn + dryRun = true + summarize = false + case dryRun: + actionFn = nil + } + out := o.Out + + result := o.Builder.Do() + if result.Err() != nil { + return result.Err() + } + + // Ignore any resource that does not support GET + result.IgnoreErrors(errors.IsMethodNotSupported, errors.IsNotFound) + + t := migrateTracker{ + out: out, + migrateFn: fn, + actionFn: actionFn, + dryRun: dryRun, + + resourcesWithErrors: sets.NewString(), + } + + err := result.Visit(func(info *resource.Info, err error) error { + if err == nil && o.FilterFn != nil { + var ok bool + t.found++ + if ok, err = o.FilterFn(info); err == nil && !ok { + t.ignored++ + if glog.V(2) { + t.report("ignored:", info, nil) + } + return nil + } + } + if err != nil { + t.resourcesWithErrors.Insert(info.Mapping.Resource) + t.errors++ + t.report("error:", info, err) + return nil + } + t.attempt(info, 10) + return nil + }) + + if summarize { + if dryRun { + fmt.Fprintf(out, "summary (DRY RUN): total=%d errors=%d ignored=%d unchanged=%d migrated=%d\n", t.found, t.errors, t.ignored, t.unchanged, t.found-t.errors-t.unchanged-t.ignored) + } else { + fmt.Fprintf(out, "summary: total=%d errors=%d ignored=%d unchanged=%d migrated=%d\n", t.found, t.errors, t.ignored, t.unchanged, t.found-t.errors-t.unchanged-t.ignored) + } + } + + if t.resourcesWithErrors.Len() > 0 { + fmt.Fprintf(out, "info: to rerun only failing resources, add --include=%s\n", strings.Join(t.resourcesWithErrors.List(), ",")) + } + + switch { + case err != nil: + fmt.Fprintf(out, "error: exited without processing all resources: %v\n", err) + err = cmdutil.ErrExit + case t.errors > 0: + fmt.Fprintf(out, "error: %d resources failed to migrate\n", t.errors) + err = cmdutil.ErrExit + } + return err +} + +// ErrUnchanged may be returned by MigrateActionFunc to indicate that the object +// did not need migration (but that could only be determined when the action was taken). +var ErrUnchanged = fmt.Errorf("migration was not necessary") + +// ErrRecalculate may be returned by MigrateActionFunc to indicate that the object +// has changed and needs to have its information recalculated prior to being saved. +// Use when a resource requries multiple API operations to persist (for instance, +// both status and spec must be changed). +var ErrRecalculate = fmt.Errorf("recalculate migration") + +// ErrRetriable is a wrapper for an error that a migrator may use to indicate the +// specific error can be retried. +type ErrRetriable struct { + error +} + +func (ErrRetriable) Temporary() bool { return true } + +// ErrNotRetriable is a wrapper for an error that a migrator may use to indicate the +// specific error cannot be retried. +type ErrNotRetriable struct { + error +} + +func (ErrNotRetriable) Temporary() bool { return false } + +type temporary interface { + // Temporary should return true if this is a temporary error + Temporary() bool +} + +// attemptResult is an enumeration of the result of a migration +type attemptResult int + +const ( + attemptResultSuccess attemptResult = iota + attemptResultError + attemptResultUnchanged + attemptResultIgnore +) + +// migrateTracker abstracts transforming and saving resources and can be used to keep track +// of how many total resources have been updated. +type migrateTracker struct { + out io.Writer + migrateFn MigrateVisitFunc + actionFn MigrateActionFunc + dryRun bool + + found, ignored, unchanged, errors int + retries int + + resourcesWithErrors sets.String +} + +// report prints a message to out that includes info about the current resource. If the optional error is +// provided it will be written as well. +func (t *migrateTracker) report(prefix string, info *resource.Info, err error) { + ns := info.Namespace + if len(ns) > 0 { + ns = "-n " + ns + } + if err != nil { + fmt.Fprintf(t.out, "%-10s %s/%s %s: %v\n", prefix, info.Mapping.Resource, info.Name, ns, err) + } else { + fmt.Fprintf(t.out, "%-10s %s/%s %s\n", prefix, info.Mapping.Resource, info.Name, ns) + } +} + +// attempt will try to invoke the migrateFn and saveFn on info, retrying any recalculation requests up +// to retries times. +func (t *migrateTracker) attempt(info *resource.Info, retries int) { + t.found++ + t.retries = retries + result, err := t.try(info) + switch { + case err != nil: + t.resourcesWithErrors.Insert(info.Mapping.Resource) + t.errors++ + t.report("error:", info, err) + case result == attemptResultIgnore: + t.ignored++ + if glog.V(2) { + t.report("ignored:", info, nil) + } + case result == attemptResultUnchanged: + t.unchanged++ + if glog.V(2) { + t.report("unchanged:", info, nil) + } + case result == attemptResultSuccess: + if glog.V(1) { + if t.dryRun { + t.report("migrated (DRY RUN):", info, nil) + } else { + t.report("migrated:", info, nil) + } + } + } +} + +// try will mutate the info and attempt to save, recalculating if there are any retries left. +// The result of the attempt or an error will be returned. +func (t *migrateTracker) try(info *resource.Info) (attemptResult, error) { + reporter, err := t.migrateFn(info) + if err != nil { + return attemptResultError, err + } + if reporter == nil { + return attemptResultIgnore, nil + } + if !reporter.Changed() { + return attemptResultUnchanged, nil + } + if t.actionFn != nil { + if err := t.actionFn(info, reporter); err != nil { + if err == ErrUnchanged { + return attemptResultUnchanged, nil + } + if canRetry(err) { + if t.retries > 0 { + if glog.V(1) && err != ErrRecalculate { + t.report("retry:", info, err) + } + result, err := t.try(info) + switch result { + case attemptResultUnchanged, attemptResultIgnore: + result = attemptResultSuccess + } + return result, err + } + } + return attemptResultError, err + } + } + return attemptResultSuccess, nil +} + +// canRetry returns true if the provided error indicates a retry is possible. +func canRetry(err error) bool { + if temp, ok := err.(temporary); ok && temp.Temporary() { + return true + } + return err == ErrRecalculate +} + +// DefaultRetriable adds retry information to the provided error, and will refresh the +// info if the client info is stale. If the refresh fails the error is made fatal. +// All other errors are left in their natural state - they will not be retried unless +// they define a Temporary() method that returns true. +func DefaultRetriable(info *resource.Info, err error) error { + if err == nil { + return nil + } + switch { + case errors.IsMethodNotSupported(err): + return ErrNotRetriable{err} + case errors.IsConflict(err): + if refreshErr := info.Get(); refreshErr != nil { + return ErrNotRetriable{err} + } + return ErrRetriable{err} + case errors.IsServerTimeout(err): + return ErrRetriable{err} + } + return err +} diff --git a/pkg/cmd/admin/migrate/storage/storage.go b/pkg/cmd/admin/migrate/storage/storage.go new file mode 100644 index 000000000000..e5c8a9a9a041 --- /dev/null +++ b/pkg/cmd/admin/migrate/storage/storage.go @@ -0,0 +1,181 @@ +package images + +import ( + "fmt" + "io" + + "github.com/golang/glog" + "github.com/spf13/cobra" + + "k8s.io/kubernetes/pkg/api/meta" + "k8s.io/kubernetes/pkg/api/unversioned" + kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/util/sets" + + "github.com/openshift/origin/pkg/cmd/admin/migrate" + "github.com/openshift/origin/pkg/cmd/util/clientcmd" +) + +const ( + internalMigrateStorageLong = ` +Migrate internal object storage via update + +This command invokes an update operation on every API object reachable by the caller. This forces +the server to write to the underlying storage if the object representation has changed. Use this +command to ensure that the most recent storage changes have been applied to all objects (storage +version, storage encoding, any newer object defaults). + +To operate on a subset of resources, use the --include flag. If you encounter errors during a run +the command will output a list of resources that received errors, which you can then re-run the +command on. You may also specify --from-key and --to-key to restrict the set of resource names +to operate on (key is NAMESPACE/NAME for resources in namespaces or NAME for cluster scoped +resources). --from-key is inclusive if specified, while --to-key is exclusive. + +By default, events are not migrated since they expire within a very short period of time. If you +have significantly increased the expiration time of events, run a migration with --include=events + +WARNING: This is a slow command and will put significant load on an API server. It may also + result in significant intra-cluster traffic.` + + internalMigrateStorageExample = ` # Perform a dry-run of updating all objects + %[1]s + + # To actually perform the update, the confirm flag must be appended + %[1]s --confirm + + # Only migrate pods + %[1]s --include=pods --confirm + + # Only pods that are in namespaces starting with "bar" + %[1]s --include=pods --confirm --from-key=bar/ --to-key=bar/\xFF +` +) + +type MigrateAPIStorageOptions struct { + migrate.ResourceOptions +} + +// NewCmdMigrateAPIStorage implements a MigrateStorage command +func NewCmdMigrateAPIStorage(name, fullName string, f *clientcmd.Factory, in io.Reader, out, errout io.Writer) *cobra.Command { + options := &MigrateAPIStorageOptions{ + ResourceOptions: migrate.ResourceOptions{ + In: in, + Out: out, + ErrOut: errout, + + Include: []string{"*"}, + DefaultExcludes: []unversioned.GroupResource{ + {Resource: "appliedclusterresourcequotas"}, + {Resource: "bindings"}, + {Resource: "deploymentconfigrollbacks"}, + {Resource: "events"}, + {Resource: "imagestreamimages"}, {Resource: "imagestreamtags"}, {Resource: "imagestreammappings"}, {Resource: "imagestreamimports"}, + {Resource: "projectrequests"}, {Resource: "projects"}, + {Resource: "componentstatuses"}, + {Resource: "clusterrolebindings"}, {Resource: "rolebindings"}, + {Resource: "clusterroles"}, {Resource: "roles"}, + {Resource: "resourceaccessreviews"}, {Resource: "localresourceaccessreviews"}, {Resource: "subjectaccessreviews"}, + {Resource: "selfsubjectrulesreviews"}, {Resource: "localsubjectaccessreviews"}, + {Resource: "replicationcontrollerdummies.extensions"}, + {Resource: "podtemplates"}, + {Resource: "useridentitymappings"}, + }, + // Resources known to share the same storage + OverlappingResources: []sets.String{ + sets.NewString("horizontalpodautoscalers.autoscaling", "horizontalpodautoscalers.extensions"), + sets.NewString("jobs.batch", "jobs.extensions"), + }, + }, + } + cmd := &cobra.Command{ + Use: fmt.Sprintf("%s REGISTRY/NAME=REGISTRY/NAME [...]", name), + Short: "Update the stored version of API objects", + Long: internalMigrateStorageLong, + Example: fmt.Sprintf(internalMigrateStorageExample, fullName), + Run: func(cmd *cobra.Command, args []string) { + kcmdutil.CheckErr(options.Complete(f, cmd, args)) + kcmdutil.CheckErr(options.Validate()) + kcmdutil.CheckErr(options.Run()) + }, + } + options.ResourceOptions.Bind(cmd) + + return cmd +} + +func (o *MigrateAPIStorageOptions) Complete(f *clientcmd.Factory, c *cobra.Command, args []string) error { + o.ResourceOptions.SaveFn = o.save + if err := o.ResourceOptions.Complete(f, c); err != nil { + return err + } + return nil +} + +func (o MigrateAPIStorageOptions) Validate() error { + return o.ResourceOptions.Validate() +} + +func (o MigrateAPIStorageOptions) Run() error { + return o.ResourceOptions.Visitor().Visit(func(info *resource.Info) (migrate.Reporter, error) { + return o.transform(info.Object) + }) +} + +// save invokes the API to alter an object. The reporter passed to this method is the same returned by +// the migration visitor method (for this type, transformAPIStorage). It should return an error +// if the input type cannot be saved. It returns migrate.ErrRecalculate if migration should be re-run +// on the provided object. +func (o *MigrateAPIStorageOptions) save(info *resource.Info, reporter migrate.Reporter) error { + switch info.Object.(type) { + // TODO: add any custom mutations necessary + default: + // load the body and save it back, without transformation to avoid losing fields + get := info.Client.Get(). + Resource(info.Mapping.Resource). + NamespaceIfScoped(info.Namespace, info.Mapping.Scope.Name() == meta.RESTScopeNameNamespace). + Name(info.Name).Do() + data, err := get.Raw() + if err != nil { + return migrate.DefaultRetriable(info, err) + } + update := info.Client.Put(). + Resource(info.Mapping.Resource). + NamespaceIfScoped(info.Namespace, info.Mapping.Scope.Name() == meta.RESTScopeNameNamespace). + Name(info.Name).Body(data). + Do() + if err := update.Error(); err != nil { + return migrate.DefaultRetriable(info, err) + } + + if oldObject, err := get.Get(); err == nil { + info.Refresh(oldObject, true) + oldVersion := info.ResourceVersion + if object, err := update.Get(); err == nil { + info.Refresh(object, true) + if info.ResourceVersion == oldVersion { + return migrate.ErrUnchanged + } + } else { + glog.V(4).Infof("unable to calculate resource version: %v", err) + } + } else { + glog.V(4).Infof("unable to calculate resource version: %v", err) + } + } + return nil +} + +// transform checks image references on the provided object and returns either a reporter (indicating +// that the object was recognized and whether it was updated) or an error. +func (o *MigrateAPIStorageOptions) transform(obj runtime.Object) (migrate.Reporter, error) { + return reporter(true), nil +} + +// reporter implements the Reporter interface for a boolean. +type reporter bool + +func (r reporter) Changed() bool { + return bool(r) +} diff --git a/pkg/cmd/cli/cli.go b/pkg/cmd/cli/cli.go index d1739d24a743..c91d98e54384 100644 --- a/pkg/cmd/cli/cli.go +++ b/pkg/cmd/cli/cli.go @@ -149,7 +149,7 @@ func NewCommandCLI(name, fullName string, in io.Reader, out, errout io.Writer) * { Message: "Advanced Commands:", Commands: []*cobra.Command{ - admin.NewCommandAdmin("adm", fullName+" "+"adm", out, errout), + admin.NewCommandAdmin("adm", fullName+" "+"adm", in, out, errout), cmd.NewCmdCreate(fullName, f, out), cmd.NewCmdReplace(fullName, f, out), cmd.NewCmdApply(fullName, f, out), diff --git a/pkg/cmd/openshift/openshift.go b/pkg/cmd/openshift/openshift.go index e8cf8b0e59f2..5145890cb5a5 100644 --- a/pkg/cmd/openshift/openshift.go +++ b/pkg/cmd/openshift/openshift.go @@ -69,7 +69,7 @@ func CommandFor(basename string) *cobra.Command { case "oc", "osc": cmd = cli.NewCommandCLI(basename, basename, in, out, errout) case "oadm", "osadm": - cmd = admin.NewCommandAdmin(basename, basename, out, errout) + cmd = admin.NewCommandAdmin(basename, basename, in, out, errout) case "kubectl": cmd = cli.NewCmdKubectl(basename, out) case "kube-apiserver": @@ -113,7 +113,7 @@ func NewCommandOpenShift(name string) *cobra.Command { startAllInOne, _ := start.NewCommandStartAllInOne(name, out) root.AddCommand(startAllInOne) - root.AddCommand(admin.NewCommandAdmin("admin", name+" admin", out, errout)) + root.AddCommand(admin.NewCommandAdmin("admin", name+" admin", in, out, errout)) root.AddCommand(cli.NewCommandCLI("cli", name+" cli", in, out, errout)) root.AddCommand(cli.NewCmdKubectl("kube", out)) root.AddCommand(newExperimentalCommand("ex", name+" ex")) diff --git a/pkg/cmd/util/clientcmd/factory.go b/pkg/cmd/util/clientcmd/factory.go index 48058c564a95..f7ec1bb6daba 100644 --- a/pkg/cmd/util/clientcmd/factory.go +++ b/pkg/cmd/util/clientcmd/factory.go @@ -430,6 +430,20 @@ func NewFactory(clientConfig kclientcmd.ClientConfig) *Factory { return kAttachablePodForObjectFunc(object) } } + kUpdatePodSpecForObject := w.Factory.UpdatePodSpecForObject + w.UpdatePodSpecForObject = func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) { + switch t := obj.(type) { + case *deployapi.DeploymentConfig: + template := t.Spec.Template + if template == nil { + t.Spec.Template = template + template = &api.PodTemplateSpec{} + } + return true, fn(&template.Spec) + default: + return kUpdatePodSpecForObject(obj, fn) + } + } kProtocolsForObject := w.Factory.ProtocolsForObject w.ProtocolsForObject = func(object runtime.Object) (map[string]string, error) { switch t := object.(type) { @@ -604,31 +618,6 @@ func (f *Factory) ExtractFileContents(obj runtime.Object) (map[string][]byte, bo } } -// UpdatePodSpecForObject update the pod specification for the provided object -// TODO: move to upstream -func (f *Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) { - // TODO: replace with a swagger schema based approach (identify pod template via schema introspection) - switch t := obj.(type) { - case *api.Pod: - return true, fn(&t.Spec) - case *api.PodTemplate: - return true, fn(&t.Template.Spec) - case *api.ReplicationController: - if t.Spec.Template == nil { - t.Spec.Template = &api.PodTemplateSpec{} - } - return true, fn(&t.Spec.Template.Spec) - case *deployapi.DeploymentConfig: - template := t.Spec.Template - if template == nil { - template = &api.PodTemplateSpec{} - } - return true, fn(&template.Spec) - default: - return false, fmt.Errorf("the object is not a pod or does not have a pod template") - } -} - // ApproximatePodTemplateForObject returns a pod template object for the provided source. // It may return both an error and a object. It attempt to return the best possible template // available at the current time. diff --git a/pkg/image/api/helper.go b/pkg/image/api/helper.go index 66d8fbd090d4..661fdac78e9d 100644 --- a/pkg/image/api/helper.go +++ b/pkg/image/api/helper.go @@ -184,6 +184,7 @@ func ParseDockerImageReference(spec string) (DockerImageReference, error) { ref.ID = id break default: + // TODO: this is no longer true with V2 return ref, fmt.Errorf("the docker pull spec %q must be two or three segments separated by slashes", spec) } diff --git a/test/cmd/migrate.sh b/test/cmd/migrate.sh new file mode 100755 index 000000000000..e05928d44ba8 --- /dev/null +++ b/test/cmd/migrate.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. +source "${OS_ROOT}/hack/lib/init.sh" +os::log::stacktrace::install +trap os::test::junit::reconcile_output EXIT + +# Cleanup cluster resources created by this test +( + set +e + oc delete all --all + exit 0 +) &>/dev/null + +os::test::junit::declare_suite_start "cmd/migrate" +# This test validates storage migration + +os::cmd::expect_success 'oc login -u system:admin' + +os::test::junit::declare_suite_start "cmd/migrate/storage" +os::cmd::expect_success_and_text 'oadm migrate storage' 'summary \(DRY RUN\)' +os::cmd::expect_success_and_text 'oadm migrate storage --loglevel=2' 'migrated \(DRY RUN\): serviceaccounts/deployer' +os::cmd::expect_success_and_not_text 'oadm migrate storage --loglevel=2 --include=pods' 'migrated \(DRY RUN\): serviceaccounts/deployer' +os::cmd::expect_success_and_text 'oadm migrate storage --loglevel=2 --include=sa --from-key=default/ --to-key=default/\xFF' 'migrated \(DRY RUN\): serviceaccounts/deployer' +os::cmd::expect_success_and_not_text 'oadm migrate storage --loglevel=2 --include=sa --from-key=default/ --to-key=default/deployer' 'migrated \(DRY RUN\): serviceaccounts/deployer' +os::cmd::expect_success_and_text 'oadm migrate storage --loglevel=2 --confirm' 'unchanged:' +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/migrate/imagereferences" +# create alternating items in history +os::cmd::expect_success 'oc import-image --from=mysql:latest test:1 --confirm' +os::cmd::expect_success 'oc tag --source=docker php:latest test:1' +os::cmd::expect_success 'oc tag --source=docker mysql:latest test:1' +os::cmd::expect_success 'oc import-image --from=php:latest test:2 --confirm' +os::cmd::expect_success 'oc tag --source=docker mysql:latest test:2' +os::cmd::expect_success 'oc tag --source=docker php:latest test:2' +os::cmd::expect_success 'oc tag --source=docker myregistry.com/php:latest test:3' +# verify error cases +os::cmd::expect_failure_and_text 'oadm migrate image-references' 'at least one mapping argument must be specified: REGISTRY/NAME=REGISTRY/NAME' +os::cmd::expect_failure_and_text 'oadm migrate image-references my.docker.io=docker.io/* --loglevel=1' 'all arguments' +os::cmd::expect_failure_and_text 'oadm migrate image-references my.docker.io/=docker.io/* --loglevel=1' 'not a valid source' +os::cmd::expect_failure_and_text 'oadm migrate image-references /*=docker.io/* --loglevel=1' 'not a valid source' +os::cmd::expect_failure_and_text 'oadm migrate image-references my.docker.io/*=docker.io --loglevel=1' 'all arguments' +os::cmd::expect_failure_and_text 'oadm migrate image-references my.docker.io/*=docker.io/ --loglevel=1' 'not a valid target' +os::cmd::expect_failure_and_text 'oadm migrate image-references my.docker.io/*=/x --loglevel=1' 'not a valid target' +os::cmd::expect_failure_and_text 'oadm migrate image-references my.docker.io/*=*/* --loglevel=1' 'at least one change' +os::cmd::expect_failure_and_text 'oadm migrate image-references a/b=a/b --loglevel=1' 'at least one field' +os::cmd::expect_failure_and_text 'oadm migrate image-references */*=*/* --loglevel=1' 'at least one change' +# verify dry run +os::cmd::expect_success_and_text 'oadm migrate image-references my.docker.io/*=docker.io/* --loglevel=1' 'migrated=0' +os::cmd::expect_success_and_text 'oadm migrate image-references --include=imagestreams docker.io/*=my.docker.io/* --loglevel=1' 'migrated \(DRY RUN\): imagestreams/test -n ' +os::cmd::expect_success_and_text 'oadm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/* --all-namespaces=false --loglevel=1' 'migrated=1' +os::cmd::expect_success_and_text 'oadm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/* --all-namespaces=false --loglevel=1 -o yaml' 'dockerImageReference: my.docker.io/mysql@sha256:' +os::cmd::expect_success_and_text 'oadm migrate image-references --include=imagestreams docker.io/other=my.docker.io/* --all-namespaces=false --loglevel=1' 'migrated=0' +# only mysql references are changed +os::cmd::expect_success_and_text 'oadm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/mysql2 --all-namespaces=false --loglevel=1 --confirm' 'migrated=1' +os::cmd::expect_success_and_text 'oc get istag test:1 --template "{{ .image.dockerImageReference }}"' '^my.docker.io/mysql2@sha256:' +os::cmd::expect_success_and_text 'oc get istag test:2 --template "{{ .image.dockerImageReference }}"' '^php@sha256:' +# all items in history are changed +os::cmd::expect_success_and_text 'oadm migrate image-references --include=imagestreams docker.io/*=my.docker.io/* --all-namespaces=false --loglevel=1 --confirm' 'migrated=1' +os::cmd::expect_success_and_not_text 'oc get is test --template "{{ range .status.tags }}{{ range .items }}{{ .dockerImageReference }}{{ \"\n\" }}{{ end }}{{ end }}"' '^php' +os::cmd::expect_success_and_not_text 'oc get is test --template "{{ range .status.tags }}{{ range .items }}{{ .dockerImageReference }}{{ \"\n\" }}{{ end }}{{ end }}"' '^mysql' +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_end + diff --git a/tools/gendocs/gen_openshift_docs.go b/tools/gendocs/gen_openshift_docs.go index 71ca8a539979..307ff62aa475 100644 --- a/tools/gendocs/gen_openshift_docs.go +++ b/tools/gendocs/gen_openshift_docs.go @@ -51,6 +51,6 @@ func main() { gendocs.GenDocs(cmd, outFile) outFile = outDir + "oadm_by_example_content.adoc" - cmd = admin.NewCommandAdmin("oadm", "oadm", ioutil.Discard, ioutil.Discard) + cmd = admin.NewCommandAdmin("oadm", "oadm", &bytes.Buffer{}, ioutil.Discard, ioutil.Discard) gendocs.GenDocs(cmd, outFile) } diff --git a/tools/genman/gen_man.go b/tools/genman/gen_man.go index 074e3928599c..a3f257bf61a5 100644 --- a/tools/genman/gen_man.go +++ b/tools/genman/gen_man.go @@ -45,7 +45,7 @@ func main() { } else if strings.HasSuffix(os.Args[2], "openshift") { genCmdMan("openshift", openshift.NewCommandOpenShift("openshift")) } else if strings.HasSuffix(os.Args[2], "oadm") { - genCmdMan("oadm", admin.NewCommandAdmin("oadm", "oadm", os.Stdout, ioutil.Discard)) + genCmdMan("oadm", admin.NewCommandAdmin("oadm", "oadm", &bytes.Buffer{}, os.Stdout, ioutil.Discard)) } else { fmt.Fprintf(os.Stderr, "Root command not specified (os | oadm | openshift).") os.Exit(1)