github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/organization/organization.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package organization 21 22 import ( 23 "encoding/json" 24 "fmt" 25 "strings" 26 27 "github.com/jedib0t/go-pretty/v6/table" 28 "github.com/pkg/errors" 29 "github.com/spf13/cobra" 30 "gopkg.in/yaml.v2" 31 "k8s.io/cli-runtime/pkg/genericiooptions" 32 cmdutil "k8s.io/kubectl/pkg/cmd/util" 33 "k8s.io/kubectl/pkg/util/templates" 34 35 "github.com/1aal/kubeblocks/pkg/cli/printer" 36 ) 37 38 var organizationExample = templates.Examples(` 39 // Get the organization name currently used by the user. 40 kbcli org current 41 // List all organizations the current user has joined. 42 kbcli org list 43 // Get the description information of organization org1. 44 kbcli org describe org1 45 // Switch to organization org2. 46 kbcli org switch org2 47 `) 48 49 const ( 50 APIURL = "http://a8ff89cbeec444c82b90c5f83a117b39-16361bbd933bde33.elb.cn-northwest-1.amazonaws.com.cn:8086" 51 APIPath = "api/v1" 52 ) 53 54 type Organizations struct { 55 Items []OrgItem `json:"items"` 56 } 57 58 type OrgItem struct { 59 ID string `json:"id"` 60 Name string `json:"name"` 61 Role string `json:"role"` 62 Description string `json:"description"` 63 DisplayName string `json:"displayName"` 64 CreatedAt string `json:"createdAt"` 65 UpdatedAt string `json:"updatedAt"` 66 } 67 68 type CurrentOrgAndContext struct { 69 CurrentOrganization string `json:"currentOrganization"` 70 CurrentContext string `json:"currentContext"` 71 } 72 73 type Organization interface { 74 getOrganization(name string) (*OrgItem, error) 75 GetOrganizations() (*Organizations, error) 76 switchOrganization(name string) (string, error) 77 getCurrentOrganization() (string, error) 78 addOrganization(body []byte) error 79 deleteOrganization(name string) error 80 IsValidOrganization(name string) (bool, error) 81 } 82 83 type OrganizationOption struct { 84 Name string 85 OutputFormat string 86 Organization Organization 87 88 genericiooptions.IOStreams 89 } 90 91 func newOrganizationOption(streams genericiooptions.IOStreams) *OrganizationOption { 92 return &OrganizationOption{ 93 IOStreams: streams, 94 } 95 } 96 97 func NewOrganizationCmd(streams genericiooptions.IOStreams) *cobra.Command { 98 cmd := &cobra.Command{ 99 Use: "org", 100 Short: "kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud.", 101 Example: organizationExample, 102 } 103 cmd.AddCommand( 104 newOrgListCmd(streams), 105 newOrgSwitchCmd(streams), 106 newOrgCurrentCmd(streams), 107 newOrgDescribeCmd(streams), 108 ) 109 110 return cmd 111 } 112 113 func newOrgListCmd(streams genericiooptions.IOStreams) *cobra.Command { 114 o := newOrganizationOption(streams) 115 116 cmd := &cobra.Command{ 117 Use: "list", 118 Short: "List all organizations you have joined.", 119 Run: func(cmd *cobra.Command, args []string) { 120 cmdutil.CheckErr(o.complete(args)) 121 cmdutil.CheckErr(o.validate(cmd)) 122 cmdutil.CheckErr(o.runList()) 123 }, 124 } 125 126 return cmd 127 } 128 129 func newOrgSwitchCmd(streams genericiooptions.IOStreams) *cobra.Command { 130 o := newOrganizationOption(streams) 131 132 cmd := &cobra.Command{ 133 Use: "switch", 134 Short: "Switch to another organization you are already a member of.", 135 Run: func(cmd *cobra.Command, args []string) { 136 cmdutil.CheckErr(o.complete(args)) 137 cmdutil.CheckErr(o.validate(cmd)) 138 cmdutil.CheckErr(o.runSwitch()) 139 }, 140 } 141 142 return cmd 143 } 144 145 func newOrgCurrentCmd(streams genericiooptions.IOStreams) *cobra.Command { 146 o := newOrganizationOption(streams) 147 148 cmd := &cobra.Command{ 149 Use: "current", 150 Short: "Get current organization.", 151 Run: func(cmd *cobra.Command, args []string) { 152 cmdutil.CheckErr(o.complete(args)) 153 cmdutil.CheckErr(o.validate(cmd)) 154 cmdutil.CheckErr(o.runCurrent()) 155 }, 156 } 157 158 return cmd 159 } 160 161 func newOrgDescribeCmd(streams genericiooptions.IOStreams) *cobra.Command { 162 o := newOrganizationOption(streams) 163 164 cmd := &cobra.Command{ 165 Use: "describe", 166 Short: "Get the description information of an organization.", 167 Run: func(cmd *cobra.Command, args []string) { 168 cmdutil.CheckErr(o.complete(args)) 169 cmdutil.CheckErr(o.validate(cmd)) 170 cmdutil.CheckErr(o.runDescribe()) 171 }, 172 } 173 174 cmd.Flags().StringVarP(&o.OutputFormat, "output", "o", "human", "Output format (human|yaml|json)") 175 176 return cmd 177 } 178 179 func (o *OrganizationOption) validate(cmd *cobra.Command) error { 180 if cmd.Name() == "switch" || cmd.Name() == "describe" { 181 if o.Name == "" { 182 return errors.New("Organization name is required.") 183 } 184 } 185 return nil 186 } 187 188 func (o *OrganizationOption) complete(args []string) error { 189 if len(args) > 0 { 190 o.Name = args[0] 191 } 192 193 token, err := GetToken() 194 if err != nil { 195 return err 196 } 197 198 if o.Organization == nil { 199 o.Organization = &CloudOrganization{ 200 Token: token, 201 APIURL: APIURL, 202 APIPath: APIPath, 203 } 204 } 205 206 return nil 207 } 208 209 func (o *OrganizationOption) runList() error { 210 organizations, err := o.Organization.GetOrganizations() 211 if err != nil { 212 return err 213 } 214 215 if len(organizations.Items) == 0 { 216 fmt.Fprintln(o.Out, "you are currently not join in any organization") 217 return nil 218 } 219 220 tbl := printer.NewTablePrinter(o.Out) 221 tbl.Tbl.SetColumnConfigs([]table.ColumnConfig{ 222 {Number: 5, WidthMax: 120}, 223 }) 224 tbl.SetHeader("NAME", "DISPLAYNAME", "DESCRIPTION", "ROLE", "ORGID") 225 226 for _, item := range organizations.Items { 227 tbl.AddRow(item.Name, item.DisplayName, item.Description, item.Role, item.ID) 228 } 229 230 tbl.Print() 231 return nil 232 } 233 234 func (o *OrganizationOption) runSwitch() error { 235 oldOrganizationName, err := o.Organization.switchOrganization(o.Name) 236 if err != nil { 237 return err 238 } 239 fmt.Fprintf(o.Out, "Successfully switched from %s to organization: %s\n", oldOrganizationName, o.Name) 240 return nil 241 } 242 243 func (o *OrganizationOption) runCurrent() error { 244 currentOrg, err := o.Organization.getCurrentOrganization() 245 if err != nil { 246 return err 247 } 248 fmt.Fprintf(o.Out, "Current organization: %s\n", currentOrg) 249 return nil 250 } 251 252 func (o *OrganizationOption) runDescribe() error { 253 orgItem, err := o.Organization.getOrganization(o.Name) 254 if err != nil { 255 return err 256 } 257 258 switch strings.ToLower(o.OutputFormat) { 259 case "yaml": 260 return o.printYAML(orgItem) 261 case "json": 262 return o.printJSON(orgItem) 263 case "human": 264 fallthrough 265 default: 266 return o.printTable(orgItem) 267 } 268 } 269 270 func (o *OrganizationOption) printYAML(orgItem *OrgItem) error { 271 body, err := yaml.Marshal(orgItem) 272 if err != nil { 273 return err 274 } 275 fmt.Fprintf(o.Out, "%s\n", body) 276 return nil 277 } 278 279 func (o *OrganizationOption) printJSON(orgItem *OrgItem) error { 280 body, err := json.MarshalIndent(orgItem, "", " ") 281 if err != nil { 282 return err 283 } 284 fmt.Fprintf(o.Out, "%s\n", body) 285 return nil 286 } 287 288 func (o *OrganizationOption) printTable(orgItem *OrgItem) error { 289 tbl := printer.NewTablePrinter(o.Out) 290 tbl.Tbl.SetColumnConfigs([]table.ColumnConfig{ 291 {Number: 5, WidthMax: 120}, 292 }) 293 tbl.SetHeader( 294 "NAME", 295 "DISPLAYNAME", 296 "CREATEDAT", 297 "UPDATEDAT", 298 "DESCRIPTION", 299 "ORGID", 300 "ROLE", 301 ) 302 303 tbl.AddRow( 304 orgItem.Name, 305 orgItem.DisplayName, 306 orgItem.CreatedAt, 307 orgItem.UpdatedAt, 308 orgItem.Description, 309 orgItem.ID, 310 orgItem.Role, 311 ) 312 313 tbl.Print() 314 return nil 315 }