Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: persist http proxy settings and security context on upgrades #4962

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions cmd/kots/cli/admin-console-upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
)

func AdminConsoleUpgradeCmd() *cobra.Command {
Expand Down Expand Up @@ -72,12 +73,11 @@ func AdminConsoleUpgradeCmd() *cobra.Command {
simultaneousUploads, _ := strconv.Atoi(v.GetString("airgap-upload-parallelism"))

upgradeOptions := kotsadmtypes.UpgradeOptions{
Namespace: namespace,
ForceUpgradeKurl: v.GetBool("force-upgrade-kurl"),
EnsureRBAC: v.GetBool("ensure-rbac"),
SimultaneousUploads: simultaneousUploads,
IncludeMinio: includeMinio,
StrictSecurityContext: v.GetBool("strict-security-context"),
Namespace: namespace,
ForceUpgradeKurl: v.GetBool("force-upgrade-kurl"),
EnsureRBAC: v.GetBool("ensure-rbac"),
SimultaneousUploads: simultaneousUploads,
IncludeMinio: includeMinio,

RegistryConfig: kotsadmtypes.RegistryConfig{
OverrideVersion: v.GetString("kotsadm-tag"),
Expand All @@ -88,6 +88,10 @@ func AdminConsoleUpgradeCmd() *cobra.Command {
},
}

if v.IsSet("strict-security-context") {
upgradeOptions.StrictSecurityContext = ptr.To(v.GetBool("strict-security-context"))
}

timeout, err := time.ParseDuration(v.GetString("wait-duration"))
if err != nil {
return errors.Wrap(err, "failed to parse timeout value")
Expand Down
135 changes: 77 additions & 58 deletions pkg/kotsadm/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,43 +79,20 @@ func removeNodeAPIClusterRBAC(deployOptions *types.DeployOptions, clientset *kub
return nil
}

func getAPIAutoCreateClusterToken(namespace string, clientset *kubernetes.Clientset) (string, error) {
autoCreateClusterTokenSecretVal, err := getAPIClusterToken(namespace, clientset)
func getAPIAutoCreateClusterToken(namespace string, cli kubernetes.Interface) (string, error) {
autoCreateClusterTokenSecretVal, err := getAPIClusterToken(namespace, cli)
if err != nil {
return "", errors.Wrap(err, "failed to get autocreate cluster token from secret")
} else if autoCreateClusterTokenSecretVal != "" {
return autoCreateClusterTokenSecretVal, nil
}

var containers []corev1.Container

existingDeployment, err := clientset.AppsV1().Deployments(namespace).Get(context.TODO(), "kotsadm", metav1.GetOptions{})
if err != nil && !kuberneteserrors.IsNotFound(err) {
return "", errors.Wrap(err, "failed to read deployment")
}
if err == nil {
containers = existingDeployment.Spec.Template.Spec.Containers
} else {
// deployment not found, check if there's a statefulset
existingStatefulSet, err := clientset.AppsV1().StatefulSets(namespace).Get(context.TODO(), "kotsadm", metav1.GetOptions{})
if err != nil {
return "", errors.Wrap(err, "failed to read statefulset")
}
containers = existingStatefulSet.Spec.Template.Spec.Containers
}

containerIdx := -1
for idx, c := range containers {
if c.Name == "kotsadm" {
containerIdx = idx
}
}

if containerIdx == -1 {
return "", errors.New("failed to find kotsadm container in statefulset")
container, err := getKotsadmContainer(namespace, cli)
if err != nil {
return "", errors.Wrap(err, "failed to get kotsadm container")
}

for _, env := range containers[containerIdx].Env {
for _, env := range container.Env {
if env.Name == "AUTO_CREATE_CLUSTER_TOKEN" {
return env.Value, nil
}
Expand All @@ -124,8 +101,8 @@ func getAPIAutoCreateClusterToken(namespace string, clientset *kubernetes.Client
return "", errors.New("failed to find autocreateclustertoken env on api statefulset")
}

func getKotsInstallID(namespace string, clientset *kubernetes.Clientset) (string, error) {
configMap, err := clientset.CoreV1().ConfigMaps(namespace).Get(context.TODO(), types.KotsadmConfigMap, metav1.GetOptions{})
func getKotsInstallID(namespace string, cli kubernetes.Interface) (string, error) {
configMap, err := cli.CoreV1().ConfigMaps(namespace).Get(context.TODO(), types.KotsadmConfigMap, metav1.GetOptions{})
if err != nil && !kuberneteserrors.IsNotFound(err) {
return "", errors.Wrap(err, "failed to read configmap")
}
Expand All @@ -137,35 +114,12 @@ func getKotsInstallID(namespace string, clientset *kubernetes.Clientset) (string

// configmap does not exist or does not have the installation id, check deployment or statefulset

var containers []corev1.Container

existingDeployment, err := clientset.AppsV1().Deployments(namespace).Get(context.TODO(), "kotsadm", metav1.GetOptions{})
if err != nil && !kuberneteserrors.IsNotFound(err) {
return "", errors.Wrap(err, "failed to get deployment")
}
if err == nil {
containers = existingDeployment.Spec.Template.Spec.Containers
} else {
// deployment not found, check if there's a statefulset
existingStatefulSet, err := clientset.AppsV1().StatefulSets(namespace).Get(context.TODO(), "kotsadm", metav1.GetOptions{})
if err != nil {
return "", errors.Wrap(err, "failed to get statefulset")
}
containers = existingStatefulSet.Spec.Template.Spec.Containers
}

containerIdx := -1
for idx, c := range containers {
if c.Name == "kotsadm" {
containerIdx = idx
}
}

if containerIdx == -1 {
return "", errors.New("failed to find kotsadm container")
container, err := getKotsadmContainer(namespace, cli)
if err != nil {
return "", errors.Wrap(err, "failed to get kotsadm container")
}

for _, env := range containers[containerIdx].Env {
for _, env := range container.Env {
if env.Name == "KOTS_INSTALL_ID" {
return env.Value, nil
}
Expand All @@ -176,3 +130,68 @@ func getKotsInstallID(namespace string, clientset *kubernetes.Clientset) (string
// - they were affected by a bug that removed the env var on upgrade
return "", nil
}

func getHTTPProxySettings(namespace string, cli kubernetes.Interface) (httpProxy, httpsProxy, noProxy string, err error) {
container, err := getKotsadmContainer(namespace, cli)
if err != nil {
return "", "", "", errors.Wrap(err, "failed to get kotsadm container")
}

for _, env := range container.Env {
if env.Name == "HTTP_PROXY" {
httpProxy = env.Value
}
if env.Name == "HTTPS_PROXY" {
httpsProxy = env.Value
}
if env.Name == "NO_PROXY" {
noProxy = env.Value
}
}

return httpProxy, httpsProxy, noProxy, nil
}

func hasStrictSecurityContext(namespace string, cli kubernetes.Interface) (bool, error) {
podSpec, err := getKotsadmPodSpec(namespace, cli)
if err != nil {
return false, errors.Wrap(err, "failed to get kotsadm pod spec")
}

if podSpec.SecurityContext == nil {
return false, nil
}
if podSpec.SecurityContext.RunAsNonRoot == nil {
return false, nil
}

return *podSpec.SecurityContext.RunAsNonRoot, nil
}

func getKotsadmPodSpec(namespace string, cli kubernetes.Interface) (*corev1.PodSpec, error) {
deploy, err := cli.AppsV1().Deployments(namespace).Get(context.TODO(), "kotsadm", metav1.GetOptions{})
if err == nil {
return &deploy.Spec.Template.Spec, nil
} else if !kuberneteserrors.IsNotFound(err) {
return nil, errors.Wrap(err, "failed to get deployment")
}

sts, err := cli.AppsV1().StatefulSets(namespace).Get(context.TODO(), "kotsadm", metav1.GetOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed to get statefulset")
}
return &sts.Spec.Template.Spec, nil
}

func getKotsadmContainer(namespace string, cli kubernetes.Interface) (*corev1.Container, error) {
podSpec, err := getKotsadmPodSpec(namespace, cli)
if err != nil {
return nil, errors.Wrap(err, "failed to get kotsadm pod spec")
}
for _, c := range podSpec.Containers {
if c.Name == "kotsadm" {
return &c, nil
}
}
return nil, errors.New("failed to find kotsadm container")
}
Loading
Loading