Skip to content

Commit

Permalink
feat(OSD-19729): Enables to pass a namespace as an argument at time o…
Browse files Browse the repository at this point in the history
…f login (#374)

Signed-off-by: Ameya Sathe <asathe@redhat.com>
  • Loading branch information
amej committed Apr 12, 2024
1 parent 6be5130 commit 2154c96
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ In this example, we will login to a cluster with id `123456abcdef` in production
- Run `oc` command to access the target cluster.
```
$ oc whoami
system:serviceaccount:openshift-backplane-srep:1234567
system:serviceaccount:default:1234567
```

- To login to the Management cluster for HyperShift (or) the managing Hive shard of normal OSD/ROSA cluster
Expand Down
32 changes: 28 additions & 4 deletions cmd/ocm-backplane/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"net/url"
"os"
"regexp"
"strings"

"github.com/golang-jwt/jwt/v4"
Expand All @@ -33,9 +34,10 @@ const EnvPs1 = "KUBE_PS1_CLUSTER_FUNCTION"

var (
args struct {
multiCluster bool
kubeConfigPath string
pd string
multiCluster bool
kubeConfigPath string
pd string
defaultNamespace string
}

globalOpts = &globalflags.GlobalOptions{}
Expand Down Expand Up @@ -92,6 +94,14 @@ func init() {
"",
"Login using PagerDuty incident id or html_url.",
)
flags.StringVarP(
&args.defaultNamespace,
"namespace",
"n",
"default",
"The default namespace for a user to execute commands in",
)

}

func runLogin(cmd *cobra.Command, argv []string) (err error) {
Expand Down Expand Up @@ -324,7 +334,14 @@ func runLogin(cmd *cobra.Command, argv []string) (err error) {

targetContext.AuthInfo = targetUserNickName
targetContext.Cluster = clusterName
targetContext.Namespace = "default"

if isValidKubernetesNamespace(args.defaultNamespace) {
logger.Debugln("Validating argument passed as namespace")
targetContext.Namespace = args.defaultNamespace
} else {
return fmt.Errorf("%v is not a valid namespace", args.defaultNamespace)
}

targetContextNickName := getContextNickname(targetContext.Namespace, targetContext.Cluster, targetContext.AuthInfo)

// Put user, cluster, context into rawconfig
Expand Down Expand Up @@ -494,3 +511,10 @@ func getBackplaneCNAME(backplaneURL string) (string, error) {
}
return resolution, nil
}

// isValidNamespace validates the input string against Kubernetes namespace rules.( RFC 1123 )
func isValidKubernetesNamespace(namespace string) bool {
// RFC 1123 compliant regex pattern)
pattern := `^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`
return regexp.MustCompile(pattern).MatchString(namespace)
}
29 changes: 25 additions & 4 deletions cmd/ocm-backplane/login/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ import (
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api"

cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"

"github.com/openshift/backplane-cli/pkg/backplaneapi"
backplaneapiMock "github.com/openshift/backplane-cli/pkg/backplaneapi/mocks"
"github.com/openshift/backplane-cli/pkg/cli/config"
Expand All @@ -26,6 +22,8 @@ import (
"github.com/openshift/backplane-cli/pkg/ocm"
ocmMock "github.com/openshift/backplane-cli/pkg/ocm/mocks"
"github.com/openshift/backplane-cli/pkg/utils"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api"
)

func MakeIoReader(s string) io.ReadCloser {
Expand Down Expand Up @@ -257,6 +255,29 @@ var _ = Describe("Login command", func() {
Expect(cfg.Contexts["default/test123/anonymous"].Namespace).To(Equal("default"))
})

It("when the namespace of the context is passed as an argument", func() {
err := utils.CreateTempKubeConfig(nil)
args.defaultNamespace = "default"
Expect(err).To(BeNil())
mockOcmInterface.EXPECT().GetOCMEnvironment().Return(ocmEnv, nil).AnyTimes()
mockOcmInterface.EXPECT().GetTargetCluster(testClusterID).Return(trueClusterID, testClusterID, nil)
mockOcmInterface.EXPECT().IsClusterHibernating(gomock.Eq(trueClusterID)).Return(false, nil).AnyTimes()
mockOcmInterface.EXPECT().GetOCMAccessToken().Return(&testToken, nil)
mockClientUtil.EXPECT().MakeRawBackplaneAPIClientWithAccessToken(backplaneAPIURI, testToken).Return(mockClient, nil)
mockClient.EXPECT().LoginCluster(gomock.Any(), gomock.Eq(trueClusterID)).Return(fakeResp, nil)

err = runLogin(nil, []string{testClusterID})

Expect(err).To(BeNil())

cfg, err := utils.ReadKubeconfigRaw()
Expect(err).To(BeNil())
Expect(cfg.CurrentContext).To(Equal("default/test123/anonymous"))
Expect(len(cfg.Contexts)).To(Equal(1))
Expect(cfg.Contexts["default/test123/anonymous"].Cluster).To(Equal(testClusterID))
Expect(cfg.Contexts["default/test123/anonymous"].Namespace).To(Equal(args.defaultNamespace))
})

It("Should fail when trying to find a non existent cluster", func() {
mockOcmInterface.EXPECT().GetOCMEnvironment().Return(ocmEnv, nil).AnyTimes()
mockOcmInterface.EXPECT().GetOCMAccessToken().Return(&testToken, nil).AnyTimes()
Expand Down
2 changes: 1 addition & 1 deletion docs/PS1-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ You can use the below methods to set the shell prompt, so you can learn which cl
[user@user ~ (⎈ |stg/user-test-1.zlob.s1:default)]$ date
Tue Sep 7 17:40:35 CST 2021
[user@user ~ (⎈ |stg/user-test-1.zlob.s1:default)]$ oc whoami
system:serviceaccount:openshift-backplane-srep:xxxxxxxxxxxx
system:serviceaccount:default:xxxxxxxxxxxx
~~~

## Bash
Expand Down
2 changes: 1 addition & 1 deletion docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ When executing `ocm backplane login <cluster-id>`, it will:
- Create a script file in `$HOME/.kube/ocm-token` for later use. As backplane uses OCM token for authentication, the `ocm-token` script will call `ocm token` to get a fresh access token, and feed to the `oc` command.
- Create cluster in `kubeconfig`. The `server` of the cluster points to the proxy url just received.
- Create user in `kubeconfig`. The user has an [ExecConfig](https://godoc.org/k8s.io/client-go/tools/clientcmd/api#ExecConfig) pointing to the script just created.
- Create a context using the cluster & user just created, and set it to current context.
- Create a context using the cluster, namespace passed as an argument( default: default ) & user just created, and set it to current context.

### Logout

Expand Down

0 comments on commit 2154c96

Please sign in to comment.