Skip to content

Commit

Permalink
fix: persist http proxy settings and security context on upgrades
Browse files Browse the repository at this point in the history
  • Loading branch information
emosbaugh committed Oct 22, 2024
1 parent 0f6552f commit 1993158
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 68 deletions.
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

0 comments on commit 1993158

Please sign in to comment.