garm/cmd/garm-cli/cmd/github_endpoints.go
Gabriel Adrian Samfira 6994c8ce05 Add copyright header
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 09:43:29 +00:00

315 lines
9.3 KiB
Go

// Copyright 2025 Cloudbase Solutions SRL
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package cmd
import (
"crypto/x509"
"encoding/pem"
"fmt"
"os"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClientEndpoints "github.com/cloudbase/garm/client/endpoints"
"github.com/cloudbase/garm/cmd/garm-cli/common"
"github.com/cloudbase/garm/params"
)
var githubEndpointCmd = &cobra.Command{
Use: "endpoint",
SilenceUsage: true,
Short: "Manage GitHub endpoints",
Long: `Manage GitHub endpoints.
This command allows you to configure and manage GitHub endpoints`,
Run: nil,
}
var githubEndpointListCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
SilenceUsage: true,
Short: "List GitHub endpoints",
Long: `List all configured GitHub endpoints.`,
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
newGHListReq := apiClientEndpoints.NewListGithubEndpointsParams()
response, err := apiCli.Endpoints.ListGithubEndpoints(newGHListReq, authToken)
if err != nil {
return err
}
formatEndpoints(response.Payload)
return nil
},
}
var githubEndpointShowCmd = &cobra.Command{
Use: "show",
Aliases: []string{"get"},
SilenceUsage: true,
Short: "Show GitHub endpoint",
Long: `Show details of a GitHub endpoint.`,
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires an endpoint name")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
newGHShowReq := apiClientEndpoints.NewGetGithubEndpointParams()
newGHShowReq.Name = args[0]
response, err := apiCli.Endpoints.GetGithubEndpoint(newGHShowReq, authToken)
if err != nil {
return err
}
formatOneEndpoint(response.Payload)
return nil
},
}
var githubEndpointCreateCmd = &cobra.Command{
Use: "create",
SilenceUsage: true,
Short: "Create GitHub endpoint",
Long: `Create a new GitHub endpoint.`,
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
createParams, err := parseCreateParams()
if err != nil {
return err
}
newGHCreateReq := apiClientEndpoints.NewCreateGithubEndpointParams()
newGHCreateReq.Body = createParams
response, err := apiCli.Endpoints.CreateGithubEndpoint(newGHCreateReq, authToken)
if err != nil {
return err
}
formatOneEndpoint(response.Payload)
return nil
},
}
var githubEndpointDeleteCmd = &cobra.Command{
Use: "delete",
Aliases: []string{"remove", "rm"},
SilenceUsage: true,
Short: "Delete GitHub endpoint",
Long: "Delete a GitHub endpoint",
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires an endpoint name")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
newGHDeleteReq := apiClientEndpoints.NewDeleteGithubEndpointParams()
newGHDeleteReq.Name = args[0]
if err := apiCli.Endpoints.DeleteGithubEndpoint(newGHDeleteReq, authToken); err != nil {
return err
}
return nil
},
}
var githubEndpointUpdateCmd = &cobra.Command{
Use: "update",
Short: "Update GitHub endpoint",
Long: "Update a GitHub endpoint",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires an endpoint name")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
updateParams := params.UpdateGithubEndpointParams{}
if cmd.Flags().Changed("ca-cert-path") {
cert, err := parseAndReadCABundle()
if err != nil {
return err
}
updateParams.CACertBundle = cert
}
if cmd.Flags().Changed("description") {
updateParams.Description = &endpointDescription
}
if cmd.Flags().Changed("base-url") {
updateParams.BaseURL = &endpointBaseURL
}
if cmd.Flags().Changed("upload-url") {
updateParams.UploadBaseURL = &endpointUploadURL
}
if cmd.Flags().Changed("api-base-url") {
updateParams.APIBaseURL = &endpointAPIBaseURL
}
newGHEndpointUpdateReq := apiClientEndpoints.NewUpdateGithubEndpointParams()
newGHEndpointUpdateReq.Name = args[0]
newGHEndpointUpdateReq.Body = updateParams
response, err := apiCli.Endpoints.UpdateGithubEndpoint(newGHEndpointUpdateReq, authToken)
if err != nil {
return err
}
formatOneEndpoint(response.Payload)
return nil
},
}
func init() {
githubEndpointCreateCmd.Flags().StringVar(&endpointName, "name", "", "Name of the GitHub endpoint")
githubEndpointCreateCmd.Flags().StringVar(&endpointDescription, "description", "", "Description for the github endpoint")
githubEndpointCreateCmd.Flags().StringVar(&endpointBaseURL, "base-url", "", "Base URL of the GitHub endpoint")
githubEndpointCreateCmd.Flags().StringVar(&endpointUploadURL, "upload-url", "", "Upload URL of the GitHub endpoint")
githubEndpointCreateCmd.Flags().StringVar(&endpointAPIBaseURL, "api-base-url", "", "API Base URL of the GitHub endpoint")
githubEndpointCreateCmd.Flags().StringVar(&endpointCACertPath, "ca-cert-path", "", "CA Cert Path of the GitHub endpoint")
githubEndpointListCmd.Flags().BoolVarP(&long, "long", "l", false, "Include additional info.")
githubEndpointCreateCmd.MarkFlagRequired("name")
githubEndpointCreateCmd.MarkFlagRequired("base-url")
githubEndpointCreateCmd.MarkFlagRequired("api-base-url")
githubEndpointCreateCmd.MarkFlagRequired("upload-url")
githubEndpointUpdateCmd.Flags().StringVar(&endpointDescription, "description", "", "Description for the github endpoint")
githubEndpointUpdateCmd.Flags().StringVar(&endpointBaseURL, "base-url", "", "Base URL of the GitHub endpoint")
githubEndpointUpdateCmd.Flags().StringVar(&endpointUploadURL, "upload-url", "", "Upload URL of the GitHub endpoint")
githubEndpointUpdateCmd.Flags().StringVar(&endpointAPIBaseURL, "api-base-url", "", "API Base URL of the GitHub endpoint")
githubEndpointUpdateCmd.Flags().StringVar(&endpointCACertPath, "ca-cert-path", "", "CA Cert Path of the GitHub endpoint")
githubEndpointCmd.AddCommand(
githubEndpointListCmd,
githubEndpointShowCmd,
githubEndpointCreateCmd,
githubEndpointDeleteCmd,
githubEndpointUpdateCmd,
)
githubCmd.AddCommand(githubEndpointCmd)
}
func parseAndReadCABundle() ([]byte, error) {
if endpointCACertPath == "" {
return nil, nil
}
if _, err := os.Stat(endpointCACertPath); os.IsNotExist(err) {
return nil, fmt.Errorf("CA cert file not found: %s", endpointCACertPath)
}
contents, err := os.ReadFile(endpointCACertPath)
if err != nil {
return nil, err
}
pemBlock, _ := pem.Decode(contents)
if pemBlock == nil {
return nil, fmt.Errorf("failed to decode PEM block")
}
if _, err := x509.ParseCertificates(pemBlock.Bytes); err != nil {
return nil, fmt.Errorf("failed to parse CA cert bundle: %w", err)
}
return contents, nil
}
func parseCreateParams() (params.CreateGithubEndpointParams, error) {
certBundleBytes, err := parseAndReadCABundle()
if err != nil {
return params.CreateGithubEndpointParams{}, err
}
ret := params.CreateGithubEndpointParams{
Name: endpointName,
BaseURL: endpointBaseURL,
UploadBaseURL: endpointUploadURL,
APIBaseURL: endpointAPIBaseURL,
Description: endpointDescription,
CACertBundle: certBundleBytes,
}
return ret, nil
}
func formatEndpoints(endpoints params.ForgeEndpoints) {
if outputFormat == common.OutputFormatJSON {
printAsJSON(endpoints)
return
}
t := table.NewWriter()
header := table.Row{"Name", "Base URL", "Description"}
if long {
header = append(header, "Created At", "Updated At")
}
t.AppendHeader(header)
for _, val := range endpoints {
row := table.Row{val.Name, val.BaseURL, val.Description}
if long {
row = append(row, val.CreatedAt, val.UpdatedAt)
}
t.AppendRow(row)
t.AppendSeparator()
}
fmt.Println(t.Render())
}
func formatOneEndpoint(endpoint params.ForgeEndpoint) {
if outputFormat == common.OutputFormatJSON {
printAsJSON(endpoint)
return
}
t := table.NewWriter()
header := table.Row{"Field", "Value"}
t.AppendHeader(header)
t.AppendRow([]interface{}{"Name", endpoint.Name})
t.AppendRow([]interface{}{"Description", endpoint.Description})
t.AppendRow([]interface{}{"Created At", endpoint.CreatedAt})
t.AppendRow([]interface{}{"Updated At", endpoint.UpdatedAt})
t.AppendRow([]interface{}{"Base URL", endpoint.BaseURL})
if endpoint.UploadBaseURL != "" {
t.AppendRow([]interface{}{"Upload URL", endpoint.UploadBaseURL})
}
t.AppendRow([]interface{}{"API Base URL", endpoint.APIBaseURL})
if len(endpoint.CACertBundle) > 0 {
t.AppendRow([]interface{}{"CA Cert Bundle", string(endpoint.CACertBundle)})
}
t.SetColumnConfigs([]table.ColumnConfig{
{Number: 1, AutoMerge: true},
{Number: 2, AutoMerge: false, WidthMax: 100},
})
fmt.Println(t.Render())
}