github.com/drycc/workflow-cli@v1.5.3-0.20240322092846-d4ee25983af9/cmd/resources.go (about) 1 package cmd 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "os" 7 "regexp" 8 "strconv" 9 10 "sigs.k8s.io/yaml" 11 12 "github.com/drycc/controller-sdk-go/api" 13 "github.com/drycc/controller-sdk-go/resources" 14 "github.com/drycc/workflow-cli/settings" 15 ) 16 17 // ResourceServices list resource service 18 func (d *DryccCmd) ResourcesServices(results int) error { 19 s, err := settings.Load(d.ConfigFile) 20 21 if err != nil { 22 return err 23 } 24 25 if results == defaultLimit { 26 results = s.Limit 27 } 28 services, count, err := resources.Services(s.Client, results) 29 if d.checkAPICompatibility(s.Client, err) != nil { 30 return err 31 } 32 33 if count == 0 { 34 d.Println("Could not find any services") 35 } else { 36 table := d.getDefaultFormatTable([]string{"ID", "NAME", "UPDATEABLE"}) 37 for _, service := range services { 38 table.Append([]string{ 39 service.ID, 40 service.Name, 41 strconv.FormatBool(service.Updateable), 42 }) 43 } 44 table.Render() 45 } 46 return nil 47 } 48 49 // ResourcePlans list resource plans 50 func (d *DryccCmd) ResourcesPlans(serviceName string, results int) error { 51 s, err := settings.Load(d.ConfigFile) 52 53 if err != nil { 54 return err 55 } 56 57 if results == defaultLimit { 58 results = s.Limit 59 } 60 plans, count, err := resources.Plans(s.Client, serviceName, results) 61 if d.checkAPICompatibility(s.Client, err) != nil { 62 return err 63 } 64 65 if count == 0 { 66 d.Println(fmt.Sprintf("Could not find any plans in %s service.", serviceName)) 67 } else { 68 table := d.getDefaultFormatTable([]string{"ID", "NAME", "DESCRIPTION"}) 69 for _, plan := range plans { 70 table.Append([]string{ 71 plan.ID, 72 plan.Name, 73 plan.Description, 74 }) 75 } 76 table.Render() 77 } 78 return nil 79 } 80 81 // ResourcesCreate create a resource for the application 82 func (d *DryccCmd) ResourcesCreate(appID, plan string, name string, params []string, values string) error { 83 s, appID, err := load(d.ConfigFile, appID) 84 85 if err != nil { 86 return err 87 } 88 paramsMap := make(map[string]interface{}) 89 if values != "" { 90 valueFile, err := os.Stat(values) 91 if err != nil { 92 return err 93 } 94 if valueFile.Size() == 0 { 95 return fmt.Errorf("%s is empty", values) 96 } 97 rawValues, err := os.ReadFile(values) 98 if err != nil { 99 return err 100 } 101 parsed := make(map[string]interface{}) 102 err = yaml.Unmarshal(rawValues, &parsed) 103 if err != nil { 104 return err 105 } 106 paramsMap["rawValues"] = base64.StdEncoding.EncodeToString([]byte(rawValues)) 107 } 108 109 d.Printf("Creating %s to %s... ", name, appID) 110 111 paramsMap, err = parseParams(paramsMap, params) 112 if err != nil { 113 return err 114 } 115 116 quit := progress(d.WOut) 117 resource := api.Resource{ 118 Name: name, 119 Plan: plan, 120 Options: paramsMap, 121 } 122 _, err = resources.Create(s.Client, appID, resource) 123 quit <- true 124 <-quit 125 if d.checkAPICompatibility(s.Client, err) != nil { 126 return err 127 } 128 129 d.Println("done") 130 return nil 131 } 132 133 // ResourcesList list resources in the application 134 func (d *DryccCmd) ResourcesList(appID string, results int) error { 135 s, appID, err := load(d.ConfigFile, appID) 136 137 if err != nil { 138 return err 139 } 140 141 if results == defaultLimit { 142 results = s.Limit 143 } 144 resources, count, err := resources.List(s.Client, appID, results) 145 if d.checkAPICompatibility(s.Client, err) != nil { 146 return err 147 } 148 149 if count == 0 { 150 d.Println(fmt.Sprintf("No resources found in %s app.", appID)) 151 } else { 152 table := d.getDefaultFormatTable([]string{"UUID", "NAME", "OWNER", "PLAN", "UPDATED"}) 153 for _, resource := range resources { 154 table.Append([]string{ 155 resource.UUID, 156 resource.Name, 157 resource.Owner, 158 resource.Plan, 159 resource.Updated, 160 }) 161 } 162 table.Render() 163 } 164 return nil 165 } 166 167 // ResourceGet describe a resource from the application 168 func (d *DryccCmd) ResourceGet(appID, name string) error { 169 s, appID, err := load(d.ConfigFile, appID) 170 171 if err != nil { 172 return err 173 } 174 175 //d.Printf(" %s from %s... ", name, appID) 176 177 resource, err := resources.Get(s.Client, appID, name) 178 if d.checkAPICompatibility(s.Client, err) != nil { 179 return err 180 } 181 table := d.getDefaultFormatTable([]string{}) 182 table.Append([]string{"App:", appID}) 183 table.Append([]string{"UUID:", resource.UUID}) 184 table.Append([]string{"Name:", resource.Name}) 185 table.Append([]string{"Plan:", resource.Plan}) 186 table.Append([]string{"Owner:", resource.Owner}) 187 table.Append([]string{"Status:", resource.Status}) 188 table.Append([]string{"Binding:", resource.Binding}) 189 table.Append([]string{"Data:"}) 190 for _, key := range *sortKeys(resource.Data) { 191 table.Append([]string{"", fmt.Sprintf("%s:", key), fmt.Sprintf("%s", resource.Data[key])}) 192 } 193 table.Append([]string{"Options:"}) 194 for _, key := range *sortKeys(resource.Options) { 195 table.Append([]string{"", fmt.Sprintf("%s:", key), fmt.Sprintf("%s", resource.Options[key])}) 196 } 197 table.Append([]string{"Message:", safeGetString(resource.Message)}) 198 table.Append([]string{"Created:", resource.Created}) 199 table.Append([]string{"Updated:", resource.Updated}) 200 table.Render() 201 return nil 202 } 203 204 // ResourceDelete delete a resource from the application 205 func (d *DryccCmd) ResourceDelete(appID, name, confirm string) error { 206 s, appID, err := load(d.ConfigFile, appID) 207 208 if err != nil { 209 return err 210 } 211 212 if confirm == "" { 213 d.Printf(` ! WARNING: Potentially Destructive Action 214 ! This command will destroy the resource: %s 215 ! To proceed, type "%s" or re-run this command with --confirm=%s 216 217 > `, name, name, name) 218 219 fmt.Scanln(&confirm) 220 } 221 222 if confirm != name { 223 return fmt.Errorf("resource %s does not match confirm %s, aborting", name, confirm) 224 } 225 226 d.Printf("Destroying %s...\n", name) 227 228 quit := progress(d.WOut) 229 err = resources.Delete(s.Client, appID, name) 230 quit <- true 231 <-quit 232 if d.checkAPICompatibility(s.Client, err) != nil { 233 return err 234 } 235 236 d.Println("done") 237 return nil 238 } 239 240 // ResourcePut update a resource for the application 241 func (d *DryccCmd) ResourcePut(appID, plan string, name string, params []string, values string) error { 242 s, appID, err := load(d.ConfigFile, appID) 243 244 if err != nil { 245 return err 246 } 247 paramsMap := make(map[string]interface{}) 248 if values != "" { 249 valueFile, err := os.Stat(values) 250 if err != nil { 251 return err 252 } 253 if valueFile.Size() == 0 { 254 return fmt.Errorf("%s is empty", values) 255 } 256 rawValues, err := os.ReadFile(values) 257 if err != nil { 258 return err 259 } 260 parsed := make(map[string]interface{}) 261 err = yaml.Unmarshal(rawValues, &parsed) 262 if err != nil { 263 return err 264 } 265 paramsMap["rawValues"] = base64.StdEncoding.EncodeToString([]byte(rawValues)) 266 } 267 268 d.Printf("Updating %s to %s... ", name, appID) 269 270 paramsMap, err = parseParams(paramsMap, params) 271 if err != nil { 272 return err 273 } 274 275 quit := progress(d.WOut) 276 resource := api.Resource{ 277 Plan: plan, 278 Options: paramsMap, 279 } 280 _, err = resources.Put(s.Client, appID, name, resource) 281 quit <- true 282 <-quit 283 if d.checkAPICompatibility(s.Client, err) != nil { 284 return err 285 } 286 287 d.Println("done") 288 return nil 289 } 290 291 // ResourceBind mount a resource to process of the application 292 func (d *DryccCmd) ResourceBind(appID string, name string) error { 293 s, appID, err := load(d.ConfigFile, appID) 294 295 if err != nil { 296 return err 297 } 298 299 d.Print("Binding resource... ") 300 301 quit := progress(d.WOut) 302 bindAction := api.ResourceBinding{BindAction: "bind"} 303 _, err = resources.Binding(s.Client, appID, name, bindAction) 304 quit <- true 305 <-quit 306 if d.checkAPICompatibility(s.Client, err) != nil { 307 return err 308 } 309 310 d.Print("done\n") 311 312 return nil 313 } 314 315 // ResourceUnbind resource a resource the application 316 func (d *DryccCmd) ResourceUnbind(appID string, name string) error { 317 s, appID, err := load(d.ConfigFile, appID) 318 319 if err != nil { 320 return err 321 } 322 323 d.Print("Unbinding resource... ") 324 325 quit := progress(d.WOut) 326 bindAction := api.ResourceBinding{BindAction: "unbind"} 327 _, err = resources.Binding(s.Client, appID, name, bindAction) 328 quit <- true 329 <-quit 330 if d.checkAPICompatibility(s.Client, err) != nil { 331 return err 332 } 333 334 d.Print("done\n") 335 336 return nil 337 } 338 339 // parseParams transfer params to map 340 func parseParams(paramsMap map[string]interface{}, params []string) (map[string]interface{}, error) { 341 regex := regexp.MustCompile(`^([A-z_]+[A-z0-9_]*[\.{1}[A-z0-9_]+]*)=([\s\S]*)$`) 342 for _, param := range params { 343 if regex.MatchString(param) { 344 captures := regex.FindStringSubmatch(param) 345 paramsMap[captures[1]] = captures[2] 346 } else { 347 return nil, fmt.Errorf("'%s' does not match the pattern 'key=var', ex: MODE=test", param) 348 } 349 } 350 351 return paramsMap, nil 352 }