github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/generatecontext.go (about) 1 /* 2 * Copyright 2023 The NATS Authors 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package cmd 17 18 import ( 19 "encoding/json" 20 "fmt" 21 "os" 22 "path/filepath" 23 "strings" 24 25 "github.com/nats-io/nsc/v2/cmd/store" 26 "github.com/nats-io/nsc/v2/home" 27 "github.com/spf13/cobra" 28 ) 29 30 func init() { 31 generateCmd.AddCommand(createGenerateContext()) 32 } 33 34 type GenerateContextParams struct { 35 AccountContextParams 36 user string 37 context string 38 creds string 39 operatorURL string 40 } 41 42 func createGenerateContext() *cobra.Command { 43 var params GenerateContextParams 44 cmd := &cobra.Command{ 45 Use: "context", 46 Short: "Generate nats cli user context", 47 Args: MaxArgs(0), 48 SilenceUsage: true, 49 Example: `nsc generate context --account a --user u --context contextName`, 50 RunE: func(cmd *cobra.Command, args []string) error { 51 return RunAction(cmd, args, ¶ms) 52 }, 53 } 54 cmd.Flags().StringVarP(¶ms.user, "user", "u", "", "user name") 55 cmd.Flags().StringVarP(¶ms.context, "context", "", "", "context name") 56 params.AccountContextParams.BindFlags(cmd) 57 58 return cmd 59 } 60 61 func (p *GenerateContextParams) SetDefaults(ctx ActionCtx) error { 62 p.AccountContextParams.SetDefaults(ctx) 63 if p.user == "" && p.AccountContextParams.Name != "" { 64 entries, err := ctx.StoreCtx().Store.ListEntries(store.Accounts, p.AccountContextParams.Name, store.Users) 65 if err != nil { 66 return err 67 } 68 switch len(entries) { 69 case 0: 70 return fmt.Errorf("account %q has no users", p.AccountContextParams.Name) 71 case 1: 72 p.user = entries[0] 73 } 74 } 75 76 return nil 77 } 78 79 func (p *GenerateContextParams) PreInteractive(_ ActionCtx) error { 80 return nil 81 } 82 83 func (p *GenerateContextParams) Load(ctx ActionCtx) error { 84 oc, err := ctx.StoreCtx().Store.ReadOperatorClaim() 85 if err != nil { 86 return err 87 } 88 if len(oc.OperatorServiceURLs) > 0 { 89 p.operatorURL = oc.OperatorServiceURLs[0] 90 } 91 return nil 92 } 93 94 func (p *GenerateContextParams) PostInteractive(_ ActionCtx) error { 95 return nil 96 } 97 98 func (p *GenerateContextParams) Validate(ctx ActionCtx) error { 99 if p.context == "" { 100 return fmt.Errorf("context name is required") 101 } 102 if strings.ContainsAny(p.context, "/\\") { 103 return fmt.Errorf("context name cannot contain filepath separators") 104 } 105 if p.AccountContextParams.Name == "" { 106 return fmt.Errorf("account is required") 107 } 108 if p.user == "" { 109 return fmt.Errorf("user is required") 110 } 111 if !ctx.StoreCtx().Store.Has(store.Accounts, p.AccountContextParams.Name, store.Users, store.JwtName(p.user)) { 112 return fmt.Errorf("user %q not found in %q", p.user, p.AccountContextParams.Name) 113 } 114 p.creds = ctx.StoreCtx().KeyStore.CalcUserCredsPath(p.AccountContextParams.Name, p.user) 115 if _, err := os.Stat(p.creds); err != nil { 116 return fmt.Errorf("creds file %q - doesn't exist - nsc generate creds first", p.creds) 117 } 118 return nil 119 } 120 121 type cliContext struct { 122 Nsc string `json:"nsc,omitempty"` 123 Url string `json:"url,omitempty"` 124 Creds string `json:"creds,omitempty"` 125 } 126 127 func (p *GenerateContextParams) Run(ctx ActionCtx) (store.Status, error) { 128 var s store.Status 129 natsCli := cliContext{} 130 natsCli.Creds = p.creds 131 natsCli.Nsc = fmt.Sprintf(`nsc://%s/%s/%s`, ctx.StoreCtx().Operator.Name, p.AccountContextParams.Name, p.user) 132 natsCli.Url = p.operatorURL 133 134 if err := os.MkdirAll(home.NatsCliContextDir(), 0755); err != nil { 135 s = store.ErrorStatus("failed to create context dir %q: %v", home.NatsCliContextDir(), err) 136 return s, nil 137 } 138 if !strings.HasSuffix(p.context, ".json") { 139 p.context = fmt.Sprintf("%s.json", p.context) 140 } 141 fn := filepath.Join(home.NatsCliContextDir(), p.context) 142 ctx.CurrentCmd().Println(fn) 143 bytes, err := json.Marshal(natsCli) 144 if err != nil { 145 s = store.FromError(err) 146 return s, nil 147 } 148 if err := Write(fn, bytes); err != nil { 149 s = store.ErrorStatus("failed to write context file: %v", err) 150 return s, nil 151 } 152 s = store.OKStatus("wrote nats cli context file to %#q", AbbrevHomePaths(fn)) 153 154 return s, nil 155 }