From c27ebd2b8b20fb4f6b04b7e917acc4a8d425c8a7 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Wed, 30 Oct 2024 11:39:07 +0100 Subject: [PATCH 01/17] Use Cobra's cmd.OutOrStdout() to redirect output This is needed so during testing we can grab the things that would be printed to stdout and assert them. --- cmd/aclsetup.go | 2 +- cmd/buildiso.go | 2 +- cmd/distro.go | 12 +++---- cmd/event.go | 8 ++--- cmd/file.go | 17 ++++----- cmd/hardlink.go | 2 +- cmd/image.go | 17 ++++----- cmd/import.go | 2 +- cmd/item.go | 2 +- cmd/list.go | 26 +++++++------- cmd/menu.go | 12 +++---- cmd/mgmtclass.go | 12 +++---- cmd/mkloaders.go | 2 +- cmd/package.go | 17 ++++----- cmd/profile.go | 21 ++++++----- cmd/replicate.go | 2 +- cmd/repo.go | 12 +++---- cmd/report.go | 72 ++++++++++++++++++------------------- cmd/reposync.go | 2 +- cmd/root.go | 56 ++++++++++++++--------------- cmd/setting.go | 8 ++--- cmd/signature.go | 18 +++++----- cmd/sync.go | 2 +- cmd/system.go | 23 ++++++------ cmd/utils.go | 33 ++++++++--------- cmd/validateAutoinstalls.go | 2 +- cmd/version.go | 5 +++ 27 files changed, 197 insertions(+), 192 deletions(-) diff --git a/cmd/aclsetup.go b/cmd/aclsetup.go index b55ae69..bca561b 100644 --- a/cmd/aclsetup.go +++ b/cmd/aclsetup.go @@ -44,7 +44,7 @@ var aclsetupCmd = &cobra.Command{ if err != nil { return err } - fmt.Println("Event ID: ", eventId) + fmt.Fprintln(cmd.OutOrStdout(), "Event ID: ", eventId) return nil }, } diff --git a/cmd/buildiso.go b/cmd/buildiso.go index 5ce6054..451226e 100644 --- a/cmd/buildiso.go +++ b/cmd/buildiso.go @@ -73,7 +73,7 @@ var buildisoCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Event ID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) return nil }, } diff --git a/cmd/distro.go b/cmd/distro.go index ef1ffa3..4c23a74 100644 --- a/cmd/distro.go +++ b/cmd/distro.go @@ -350,7 +350,7 @@ var distroAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Distro %s created\n", distro.Name) + fmt.Fprintf(cmd.OutOrStdout(), "Distro %s created\n", distro.Name) return nil }, } @@ -449,7 +449,7 @@ var distroListCmd = &cobra.Command{ if err != nil { return err } - listItems("distros", distroNames) + listItems(cmd, "distros", distroNames) return nil }, } @@ -515,14 +515,14 @@ var distroRenameCmd = &cobra.Command{ }, } -func reportDistros(distroNames []string) error { +func reportDistros(cmd *cobra.Command, distroNames []string) error { for _, itemName := range distroNames { distro, err := Client.GetDistro(itemName, false, false) if err != nil { return err } - printStructured(distro) - fmt.Println("") + printStructured(cmd, distro) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -546,7 +546,7 @@ var distroReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportDistros(itemNames) + return reportDistros(cmd, itemNames) }, } diff --git a/cmd/event.go b/cmd/event.go index 8a4882a..faa29e1 100644 --- a/cmd/event.go +++ b/cmd/event.go @@ -32,7 +32,7 @@ var eventStatusCmd = &cobra.Command{ if err != nil { return err } - fmt.Println(event.State) + fmt.Fprintln(cmd.OutOrStdout(), event.State) return nil }, } @@ -66,13 +66,13 @@ var eventListCmd = &cobra.Command{ stateWidth = len(event.State) } } - fmt.Printf("%*s | %*s | %*s | %*s | %s \n", idWidth, "ID", nameWidth, "Name", stateWidth, "Task State", stateTimeWidth, "Time (last transitioned)", "Read by Who") + fmt.Fprintf(cmd.OutOrStdout(), "%*s | %*s | %*s | %*s | %s \n", idWidth, "ID", nameWidth, "Name", stateWidth, "Task State", stateTimeWidth, "Time (last transitioned)", "Read by Who") for _, event := range events { stateTimeStruct, err := covertFloatToUtcTime(event.StateTime) if err != nil { return err } - fmt.Printf("%*s | %*s | %*s | %*s | %s \n", idWidth, event.ID, nameWidth, event.Name, stateWidth, event.State, stateTimeWidth, stateTimeStruct.Format(time.DateTime), event.ReadByWho) + fmt.Fprintf(cmd.OutOrStdout(), "%*s | %*s | %*s | %*s | %s \n", idWidth, event.ID, nameWidth, event.Name, stateWidth, event.State, stateTimeWidth, stateTimeStruct.Format(time.DateTime), event.ReadByWho) } return nil }, @@ -92,7 +92,7 @@ var eventLogCmd = &cobra.Command{ if err != nil { return err } - fmt.Println(eventLog) + fmt.Fprintln(cmd.OutOrStdout(), eventLog) return nil }, } diff --git a/cmd/file.go b/cmd/file.go index b379a63..2180ca5 100644 --- a/cmd/file.go +++ b/cmd/file.go @@ -142,7 +142,7 @@ var fileAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("File %s created\n", file.Name) + fmt.Fprintf(cmd.OutOrStdout(), "File %s created\n", file.Name) return nil }, } @@ -227,13 +227,14 @@ var fileListCmd = &cobra.Command{ Use: "list", Short: "list all files", Long: `Lists all available files.`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { generateCobblerClient() fileNames, err := Client.ListFileNames() if err != nil { - fmt.Println(err) + return err } - listItems("files", fileNames) + listItems(cmd, "files", fileNames) + return nil }, } @@ -289,14 +290,14 @@ var fileRenameCmd = &cobra.Command{ }, } -func reportFiles(fileNames []string) error { +func reportFiles(cmd *cobra.Command, fileNames []string) error { for _, itemName := range fileNames { file, err := Client.GetFile(itemName, false, false) if err != nil { return err } - printStructured(file) - fmt.Println("") + printStructured(cmd, file) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -320,7 +321,7 @@ var fileReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportFiles(itemNames) + return reportFiles(cmd, itemNames) }, } diff --git a/cmd/hardlink.go b/cmd/hardlink.go index f84d447..0b2deb2 100644 --- a/cmd/hardlink.go +++ b/cmd/hardlink.go @@ -20,7 +20,7 @@ var hardlinkCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Event ID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) return nil }, } diff --git a/cmd/image.go b/cmd/image.go index 0efeda4..6cad80f 100644 --- a/cmd/image.go +++ b/cmd/image.go @@ -380,7 +380,7 @@ var imageAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("System %s created\n", system.Name) + fmt.Fprintf(cmd.OutOrStdout(), "System %s created\n", system.Name) return nil }, } @@ -461,13 +461,14 @@ var imageListCmd = &cobra.Command{ Use: "list", Short: "list all images", Long: `Lists all available images.`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { generateCobblerClient() imageNames, err := Client.ListImageNames() if err != nil { - fmt.Println(err) + return err } - listItems("images", imageNames) + listItems(cmd, "images", imageNames) + return nil }, } @@ -518,14 +519,14 @@ var imageRenameCmd = &cobra.Command{ }, } -func reportImages(imageNames []string) error { +func reportImages(cmd *cobra.Command, imageNames []string) error { for _, itemName := range imageNames { system, err := Client.GetImage(itemName, false, false) if err != nil { return err } - printStructured(system) - fmt.Println("") + printStructured(cmd, system) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -549,7 +550,7 @@ var imageReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportImages(itemNames) + return reportImages(cmd, itemNames) }, } diff --git a/cmd/import.go b/cmd/import.go index 0cd5c16..bf89c71 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -65,7 +65,7 @@ See https://cobbler.readthedocs.io/en/latest/quickstart-guide.html#importing-you if err != nil { return err } - fmt.Printf("Event ID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) return nil }, } diff --git a/cmd/item.go b/cmd/item.go index 8e18171..7a8cc53 100644 --- a/cmd/item.go +++ b/cmd/item.go @@ -134,7 +134,7 @@ func FindItemNames(cmd *cobra.Command, args []string, what string) error { return err } for _, distroName := range itemNames { - fmt.Println(distroName) + fmt.Fprintln(cmd.OutOrStdout(), distroName) } return nil } diff --git a/cmd/list.go b/cmd/list.go index 42e3fbc..02bc7aa 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -56,26 +56,26 @@ Identical to 'cobbler report'`, if err != nil { return err } - listItems("distros", distroNames) - listItems("profiles", profileNames) - listItems("systems", systemNames) - listItems("repos", repoNames) - listItems("images", imageNames) - listItems("mgmtclasses", mgmtClassNames) - listItems("packages", packageNames) - listItems("files", fileNames) - listItems("menus", menuNames) + listItems(cmd, "distros", distroNames) + listItems(cmd, "profiles", profileNames) + listItems(cmd, "systems", systemNames) + listItems(cmd, "repos", repoNames) + listItems(cmd, "images", imageNames) + listItems(cmd, "mgmtclasses", mgmtClassNames) + listItems(cmd, "packages", packageNames) + listItems(cmd, "files", fileNames) + listItems(cmd, "menus", menuNames) return nil }, } -func listItems(what string, items []string) { - fmt.Printf("%s:\n", what) +func listItems(cmd *cobra.Command, what string, items []string) { + fmt.Fprintf(cmd.OutOrStdout(), "%s:\n", what) sort.Strings(items) for _, item := range items { - fmt.Printf(" %s\n", item) + fmt.Fprintf(cmd.OutOrStdout(), " %s\n", item) } - fmt.Println() + fmt.Fprintln(cmd.OutOrStdout(), "") } func init() { diff --git a/cmd/menu.go b/cmd/menu.go index 09169eb..eb9d97e 100644 --- a/cmd/menu.go +++ b/cmd/menu.go @@ -86,7 +86,7 @@ var menuAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Menu %s created\n", menu.Name) + fmt.Fprintf(cmd.OutOrStdout(), "Menu %s created\n", menu.Name) return nil }, } @@ -169,7 +169,7 @@ var menuListCmd = &cobra.Command{ if err != nil { return err } - listItems("menus", menuNames) + listItems(cmd, "menus", menuNames) return nil }, } @@ -219,14 +219,14 @@ var menuRenameCmd = &cobra.Command{ }, } -func reportMenus(menuNames []string) error { +func reportMenus(cmd *cobra.Command, menuNames []string) error { for _, itemName := range menuNames { menu, err := Client.GetMenu(itemName, false, false) if err != nil { return err } - printStructured(menu) - fmt.Println("") + printStructured(cmd, menu) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -250,7 +250,7 @@ var menuReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportMenus(itemNames) + return reportMenus(cmd, itemNames) }, } diff --git a/cmd/mgmtclass.go b/cmd/mgmtclass.go index 8091851..9981a9d 100644 --- a/cmd/mgmtclass.go +++ b/cmd/mgmtclass.go @@ -137,7 +137,7 @@ var mgmtclassAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Mgmtclass %s created\n", mgmtClass.Name) + fmt.Fprintf(cmd.OutOrStdout(), "Mgmtclass %s created\n", mgmtClass.Name) return nil }, } @@ -232,7 +232,7 @@ var mgmtclassListCmd = &cobra.Command{ if err != nil { return err } - listItems("mgmtclasses", mgmtclassNames) + listItems(cmd, "mgmtclasses", mgmtclassNames) return nil }, } @@ -289,14 +289,14 @@ var mgmtclassRenameCmd = &cobra.Command{ }, } -func reportMgmtClasses(mgmtClassNames []string) error { +func reportMgmtClasses(cmd *cobra.Command, mgmtClassNames []string) error { for _, itemName := range mgmtClassNames { system, err := Client.GetMgmtClass(itemName, false, false) if err != nil { return err } - printStructured(system) - fmt.Println("") + printStructured(cmd, system) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -320,7 +320,7 @@ var mgmtclassReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportMgmtClasses(itemNames) + return reportMgmtClasses(cmd, itemNames) }, } diff --git a/cmd/mkloaders.go b/cmd/mkloaders.go index 362424c..f0c3d38 100644 --- a/cmd/mkloaders.go +++ b/cmd/mkloaders.go @@ -23,7 +23,7 @@ The options are configured in the Cobbler settings file.`, if err != nil { return err } - fmt.Printf("Event ID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) return nil }, } diff --git a/cmd/package.go b/cmd/package.go index 6cbae59..84cf0a6 100644 --- a/cmd/package.go +++ b/cmd/package.go @@ -106,7 +106,7 @@ var packageAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Package %s created\n", linuxpackage.Name) + fmt.Fprintf(cmd.OutOrStdout(), "Package %s created\n", linuxpackage.Name) return nil }, } @@ -192,13 +192,14 @@ var packageListCmd = &cobra.Command{ Use: "list", Short: "list all packages", Long: `Lists all available packages.`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { generateCobblerClient() packageNames, err := Client.ListPackageNames() if err != nil { - fmt.Println(err) + return err } - listItems("packages", packageNames) + listItems(cmd, "packages", packageNames) + return nil }, } @@ -254,14 +255,14 @@ var packageRenameCmd = &cobra.Command{ }, } -func reportPackages(packageNames []string) error { +func reportPackages(cmd *cobra.Command, packageNames []string) error { for _, itemName := range packageNames { repo, err := Client.GetRepo(itemName, false, false) if err != nil { return err } - printStructured(repo) - fmt.Println("") + printStructured(cmd, repo) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -285,7 +286,7 @@ var packageReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportPackages(itemNames) + return reportPackages(cmd, itemNames) }, } diff --git a/cmd/profile.go b/cmd/profile.go index 7f70686..d30c4e9 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -9,7 +9,6 @@ import ( cobbler "github.com/cobbler/cobblerclient" "github.com/spf13/cobra" "github.com/spf13/pflag" - "os" ) func updateProfileFromFlags(cmd *cobra.Command, profile *cobbler.Profile) error { @@ -539,7 +538,7 @@ var profileAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Profile %s created\n", profile.Name) + fmt.Fprintf(cmd.OutOrStdout(), "Profile %s created\n", profile.Name) return nil }, } @@ -598,7 +597,7 @@ var profileDumpVarsCmd = &cobra.Command{ return err } // Print data - printDumpVars(blendedData) + printDumpVars(cmd, blendedData) return err }, } @@ -654,14 +653,14 @@ var profileGetAutoinstallCmd = &cobra.Command{ return err } if !profileExists { - fmt.Println("Profile does not exist!") - os.Exit(1) + return fmt.Errorf("Profile does not exist!") + } autoinstallRendered, err := Client.GenerateAutoinstall(profileName, "") if err != nil { return err } - fmt.Println(autoinstallRendered) + fmt.Fprintln(cmd.OutOrStdout(), autoinstallRendered) return nil }, } @@ -676,7 +675,7 @@ var profileListCmd = &cobra.Command{ if err != nil { return err } - listItems("profiles", profileNames) + listItems(cmd, "profiles", profileNames) return nil }, } @@ -736,14 +735,14 @@ var profileRenameCmd = &cobra.Command{ }, } -func reportProfiles(profileNames []string) error { +func reportProfiles(cmd *cobra.Command, profileNames []string) error { for _, itemName := range profileNames { profile, err := Client.GetProfile(itemName, false, false) if err != nil { return err } - printStructured(profile) - fmt.Println("") + printStructured(cmd, profile) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -767,7 +766,7 @@ var profileReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportProfiles(itemNames) + return reportProfiles(cmd, itemNames) }, } diff --git a/cmd/replicate.go b/cmd/replicate.go index b19b28e..993d574 100644 --- a/cmd/replicate.go +++ b/cmd/replicate.go @@ -98,7 +98,7 @@ See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-replicate for if err != nil { return err } - fmt.Printf("EventID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "EventID: %s\n", eventId) return nil }, } diff --git a/cmd/repo.go b/cmd/repo.go index 59c09af..1d56231 100644 --- a/cmd/repo.go +++ b/cmd/repo.go @@ -205,7 +205,7 @@ var repoAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Repo %s created\n", repo.Name) + fmt.Fprintf(cmd.OutOrStdout(), "Repo %s created\n", repo.Name) return nil }, } @@ -303,7 +303,7 @@ var repoListCmd = &cobra.Command{ if err != nil { return err } - listItems("repos", repoNames) + listItems(cmd, "repos", repoNames) return nil }, } @@ -359,14 +359,14 @@ var repoRenameCmd = &cobra.Command{ }, } -func reportRepos(repoNames []string) error { +func reportRepos(cmd *cobra.Command, repoNames []string) error { for _, itemName := range repoNames { repo, err := Client.GetRepo(itemName, false, false) if err != nil { return err } - printStructured(repo) - fmt.Println("") + printStructured(cmd, repo) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -390,7 +390,7 @@ var repoReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportRepos(itemNames) + return reportRepos(cmd, itemNames) }, } diff --git a/cmd/report.go b/cmd/report.go index f404642..a6bbe9e 100644 --- a/cmd/report.go +++ b/cmd/report.go @@ -20,121 +20,121 @@ Identical to 'cobbler list'`, RunE: func(cmd *cobra.Command, args []string) error { generateCobblerClient() // Distro - fmt.Println("distros:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "distros:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") distroNames, err := Client.ListDistroNames() if err != nil { return err } - err = reportDistros(distroNames) + err = reportDistros(cmd, distroNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") // Profile - fmt.Println("profiles:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "profiles:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") profileNames, err := Client.ListProfileNames() if err != nil { return err } - err = reportProfiles(profileNames) + err = reportProfiles(cmd, profileNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") // System - fmt.Println("systems:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "systems:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") systemNames, err := Client.ListSystemNames() if err != nil { return err } - err = reportSystems(systemNames) + err = reportSystems(cmd, systemNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") // Repository - fmt.Println("repos:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "repos:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") repoNames, err := Client.ListRepoNames() if err != nil { return err } - err = reportRepos(repoNames) + err = reportRepos(cmd, repoNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") // Image - fmt.Println("images:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "images:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") imageNames, err := Client.ListImageNames() if err != nil { return err } - err = reportImages(imageNames) + err = reportImages(cmd, imageNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") // Mgmtclass - fmt.Println("mgmtclasses:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "mgmtclasses:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") mgmtClassNames, err := Client.ListMgmtClassNames() if err != nil { return err } - err = reportMgmtClasses(mgmtClassNames) + err = reportMgmtClasses(cmd, mgmtClassNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") // Package - fmt.Println("packages:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "packages:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") packageNames, err := Client.ListPackageNames() if err != nil { return err } - err = reportPackages(packageNames) + err = reportPackages(cmd, packageNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") // File - fmt.Println("files:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "files:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") fileNames, err := Client.ListFileNames() if err != nil { return err } - err = reportFiles(fileNames) + err = reportFiles(cmd, fileNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") // Menu - fmt.Println("menus:") - fmt.Println("==========") + fmt.Fprintln(cmd.OutOrStdout(), "menus:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") menuNames, err := Client.ListMenuNames() if err != nil { return err } - err = reportMenus(menuNames) + err = reportMenus(cmd, menuNames) if err != nil { return err } - fmt.Println("") + fmt.Fprintln(cmd.OutOrStdout(), "") return nil }, } diff --git a/cmd/reposync.go b/cmd/reposync.go index 1cef32a..ae694c0 100644 --- a/cmd/reposync.go +++ b/cmd/reposync.go @@ -42,7 +42,7 @@ See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-reposync for m if err != nil { return err } - fmt.Printf("Event ID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) return nil }, } diff --git a/cmd/root.go b/cmd/root.go index 0a58a66..4689ee5 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -101,7 +101,7 @@ func generateCobblerClient() { } } -func printStructured(dataStruct interface{}) { +func printStructured(cmd *cobra.Command, dataStruct interface{}) { s := reflect.ValueOf(dataStruct).Elem() typeOfT := s.Type() @@ -111,12 +111,12 @@ func printStructured(dataStruct interface{}) { fieldName := typeOfT.Field(i).Name fieldStructName := typeOfT.Field(i).Type.String() if strings.HasPrefix(fieldStructName, "cobblerclient.Value") { - printValueStructured(mapstructureTag, f) + printValueStructured(cmd, mapstructureTag, f) continue } if fieldName == "Item" { baseItem := f.Interface().(cobbler.Item) - printStructured(&baseItem) + printStructured(cmd, &baseItem) continue } if fieldName == "Interfaces" { @@ -129,80 +129,80 @@ func printStructured(dataStruct interface{}) { if fieldName == "Meta" { continue } - printField(f.Kind(), mapstructureTag, f.Interface()) + printField(cmd, f.Kind(), mapstructureTag, f.Interface()) } // Print interfaces at the end of the output networkInterfacesField := s.FieldByName("Interfaces") if networkInterfacesField != (reflect.Value{}) { networkInterfaces := networkInterfacesField.Interface().(cobbler.Interfaces) - printNetworkInterface(networkInterfaces) + printNetworkInterface(cmd, networkInterfaces) } } -func printValueStructured(name string, value reflect.Value) { +func printValueStructured(cmd *cobra.Command, name string, value reflect.Value) { isInherited := value.FieldByName("IsInherited").Bool() data := value.FieldByName("Data").Interface() if isInherited { - printField(reflect.String, name, "<>") + printField(cmd, reflect.String, name, "<>") } else { dataType := value.FieldByName("Data").Kind() - printField(dataType, name, data) + printField(cmd, dataType, name, data) } } -func printNetworkInterface(networkInterface cobbler.Interfaces) { +func printNetworkInterface(cmd *cobra.Command, networkInterface cobbler.Interfaces) { for interfaceName, interfaceStruct := range networkInterface { - fmt.Printf("%-40s: %s\n", "Interface =====", interfaceName) - printStructured(&interfaceStruct) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %s\n", "Interface =====", interfaceName) + printStructured(cmd, &interfaceStruct) } } -func printField(valueType reflect.Kind, name string, value interface{}) { +func printField(cmd *cobra.Command, valueType reflect.Kind, name string, value interface{}) { if name == "ctime" || name == "mtime" { time, err := covertFloatToUtcTime(value.(float64)) if err == nil { // If there is an error just show the float - fmt.Printf("%-40s: %s\n", name, time) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %s\n", name, time) return } } switch valueType { case reflect.Bool: - fmt.Printf("%-40s: %t\n", name, value.(bool)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %t\n", name, value.(bool)) case reflect.Int64: - fmt.Printf("%-40s: %d\n", name, value.(int64)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %d\n", name, value.(int64)) case reflect.Int32: - fmt.Printf("%-40s: %d\n", name, value.(int32)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %d\n", name, value.(int32)) case reflect.Int16: - fmt.Printf("%-40s: %d\n", name, value.(int16)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %d\n", name, value.(int16)) case reflect.Int8: - fmt.Printf("%-40s: %d\n", name, value.(int8)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %d\n", name, value.(int8)) case reflect.Int: - fmt.Printf("%-40s: %d\n", name, value.(int)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %d\n", name, value.(int)) case reflect.Float32: - fmt.Printf("%-40s: %f\n", name, value.(float32)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %f\n", name, value.(float32)) case reflect.Float64: - fmt.Printf("%-40s: %f\n", name, value.(float64)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %f\n", name, value.(float64)) case reflect.Map: res2B, _ := json.Marshal(value) - fmt.Printf("%-40s: %s\n", name, string(res2B)) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %s\n", name, string(res2B)) case reflect.Array, reflect.Slice: arr := reflect.ValueOf(value) - fmt.Printf("%-40s: [", name) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: [", name) for i := 0; i < arr.Len(); i++ { if i+1 != arr.Len() { - fmt.Printf("'%v', ", arr.Index(i).Interface()) + fmt.Fprintf(cmd.OutOrStdout(), "'%v', ", arr.Index(i).Interface()) } else { - fmt.Printf("'%v'", arr.Index(i).Interface()) + fmt.Fprintf(cmd.OutOrStdout(), "'%v'", arr.Index(i).Interface()) } } - fmt.Printf("]\n") + fmt.Fprintf(cmd.OutOrStdout(), "]\n") default: if value == nil { value = "" } - fmt.Printf("%-40s: %s\n", name, value) - // fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface()) + fmt.Fprintf(cmd.OutOrStdout(), "%-40s: %s\n", name, value) + // fmt.Fprintf(cmd.OutOrStdout(),"%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface()) } } diff --git a/cmd/setting.go b/cmd/setting.go index 5418b3e..456b4be 100644 --- a/cmd/setting.go +++ b/cmd/setting.go @@ -32,7 +32,7 @@ var settingEditCmd = &cobra.Command{ return err } if !settings.AllowDynamicSettings { - fmt.Println("Dynamic settings are turned off server-side!") + fmt.Fprintln(cmd.OutOrStdout(), "Dynamic settings are turned off server-side!") os.Exit(1) } @@ -49,9 +49,9 @@ var settingEditCmd = &cobra.Command{ return err } if result == 0 { - fmt.Println("Successfully updated!") + fmt.Fprintln(cmd.OutOrStdout(), "Successfully updated!") } else { - fmt.Println("Updating settings failed!") + fmt.Fprintln(cmd.OutOrStdout(), "Updating settings failed!") } return nil }, @@ -68,7 +68,7 @@ var settingReportCmd = &cobra.Command{ return err } - printStructured(settings) + printStructured(cmd, settings) return nil }, } diff --git a/cmd/signature.go b/cmd/signature.go index 840aad4..432a824 100644 --- a/cmd/signature.go +++ b/cmd/signature.go @@ -16,7 +16,7 @@ var signatureCmd = &cobra.Command{ Short: "Signature management", Long: `Reloads, reports or updates the signatures of the distinct operating system versions.`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Please use one of the sub commands!") + fmt.Fprintln(cmd.OutOrStdout(), "Please use one of the sub commands!") _ = cmd.Help() }, } @@ -39,14 +39,14 @@ var signatureReportCmd = &cobra.Command{ var totalOsVersions int // Print signatures - fmt.Println("Currently loaded signatures") + fmt.Fprintln(cmd.OutOrStdout(), "Currently loaded signatures") breedNameList := make([]string, 0, len(signatures.Breeds)) for key := range signatures.Breeds { breedNameList = append(breedNameList, key) } sort.Strings(breedNameList) for _, breedName := range breedNameList { - fmt.Println(breedName) + fmt.Fprintln(cmd.OutOrStdout(), breedName) totalOsVersions += len(signatures.Breeds[breedName]) if len(signatures.Breeds[breedName]) > 0 { osVersionNameList := make([]string, 0, len(signatures.Breeds[breedName])) @@ -55,16 +55,16 @@ var signatureReportCmd = &cobra.Command{ } sort.Strings(osVersionNameList) for _, versionName := range osVersionNameList { - fmt.Printf("\t%s\n", versionName) + fmt.Fprintf(cmd.OutOrStdout(), "\t%s\n", versionName) } } else { - fmt.Println("\t(none)") + fmt.Fprintln(cmd.OutOrStdout(), "\t(none)") } } - fmt.Printf("\n%d breeds with %d total OS versions loaded\n", len(signatures.Breeds), totalOsVersions) + fmt.Fprintf(cmd.OutOrStdout(), "\n%d breeds with %d total OS versions loaded\n", len(signatures.Breeds), totalOsVersions) } else { - fmt.Println("No breeds found in the signature, a signature update is recommended") + fmt.Fprintln(cmd.OutOrStdout(), "No breeds found in the signature, a signature update is recommended") } return nil }, @@ -77,7 +77,7 @@ var signatureUpdateCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { generateCobblerClient() eventId, _ := Client.BackgroundSignatureUpdate() - fmt.Printf("Event ID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) }, } @@ -88,7 +88,7 @@ var signatureReloadCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { generateCobblerClient() - fmt.Println("This functionality cannot be used in the new CLI until https://github.com/cobbler/cobbler/issues/3791 is implemented!") + fmt.Fprintln(cmd.OutOrStdout(), "This functionality cannot be used in the new CLI until https://github.com/cobbler/cobbler/issues/3791 is implemented!") }, } diff --git a/cmd/sync.go b/cmd/sync.go index 9f7ce54..6a7090b 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -57,7 +57,7 @@ See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-sync for more if err != nil { return err } - fmt.Printf("Event ID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) return nil }, } diff --git a/cmd/system.go b/cmd/system.go index d228292..31efe1e 100644 --- a/cmd/system.go +++ b/cmd/system.go @@ -9,7 +9,6 @@ import ( cobbler "github.com/cobbler/cobblerclient" "github.com/spf13/cobra" "github.com/spf13/pflag" - "os" ) func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { @@ -800,7 +799,7 @@ var systemAddCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("System %s created\n", system.Name) + fmt.Fprintf(cmd.OutOrStdout(), "System %s created\n", system.Name) return nil }, } @@ -871,7 +870,7 @@ var systemDumpVarsCmd = &cobra.Command{ return err } // Print data - printDumpVars(blendedData) + printDumpVars(cmd, blendedData) return err }, } @@ -898,7 +897,6 @@ var systemEditCmd = &cobra.Command{ if err != nil { return err } - fmt.Println(updateSystem.Interfaces) if updateSystem.Meta.IsDirty { updateSystem, err = Client.GetSystem( updateSystem.Name, @@ -909,7 +907,6 @@ var systemEditCmd = &cobra.Command{ return err } } - fmt.Println(updateSystem.Interfaces) // Update the system via XML-RPC return Client.UpdateSystem(updateSystem) }, @@ -940,14 +937,14 @@ var systemGetAutoinstallCmd = &cobra.Command{ return err } if !systemExists { - fmt.Println("System does not exist!") - os.Exit(1) + //goland:noinspection GoErrorStringFormat + return fmt.Errorf("System does not exist") } autoinstallRendered, err := Client.GenerateAutoinstall("", systemName) if err != nil { return err } - fmt.Println(autoinstallRendered) + fmt.Fprintln(cmd.OutOrStdout(), autoinstallRendered) return nil }, } @@ -962,7 +959,7 @@ var systemListCmd = &cobra.Command{ if err != nil { return err } - listItems("systems", systemNames) + listItems(cmd, "systems", systemNames) return nil }, } @@ -1117,14 +1114,14 @@ var systemRenameCmd = &cobra.Command{ }, } -func reportSystems(systemNames []string) error { +func reportSystems(cmd *cobra.Command, systemNames []string) error { for _, itemName := range systemNames { system, err := Client.GetSystem(itemName, false, false) if err != nil { return err } - printStructured(system) - fmt.Println("") + printStructured(cmd, system) + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil } @@ -1148,7 +1145,7 @@ var systemReportCmd = &cobra.Command{ } else { itemNames = append(itemNames, name) } - return reportSystems(itemNames) + return reportSystems(cmd, itemNames) }, } diff --git a/cmd/utils.go b/cmd/utils.go index 4cfe981..e09c431 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -3,6 +3,7 @@ package cmd import ( "encoding/json" "fmt" + "github.com/spf13/cobra" "reflect" "strconv" "strings" @@ -34,46 +35,46 @@ func covertFloatToUtcTime(t float64) (time.Time, error) { return time.Unix(seconds, nanoSeconds).In(timezone), nil } -func printDumpVars(blendedData map[string]interface{}) { +func printDumpVars(cmd *cobra.Command, blendedData map[string]interface{}) { for key, value := range blendedData { if value == nil { - fmt.Printf("%s:\n", key) + fmt.Fprintf(cmd.OutOrStdout(), "%s:\n", key) continue } valueType := reflect.TypeOf(value).Kind() switch valueType { case reflect.Bool: - fmt.Printf("%s: %t\n", key, value.(bool)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %t\n", key, value.(bool)) case reflect.Int64: - fmt.Printf("%s: %d\n", key, value.(int64)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %d\n", key, value.(int64)) case reflect.Int32: - fmt.Printf("%s: %d\n", key, value.(int32)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %d\n", key, value.(int32)) case reflect.Int16: - fmt.Printf("%s: %d\n", key, value.(int16)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %d\n", key, value.(int16)) case reflect.Int8: - fmt.Printf("%s: %d\n", key, value.(int8)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %d\n", key, value.(int8)) case reflect.Int: - fmt.Printf("%s: %d\n", key, value.(int)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %d\n", key, value.(int)) case reflect.Float32: - fmt.Printf("%s: %f\n", key, value.(float32)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %f\n", key, value.(float32)) case reflect.Float64: - fmt.Printf("%s: %f\n", key, value.(float64)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %f\n", key, value.(float64)) case reflect.Slice, reflect.Array: arr := reflect.ValueOf(value) - fmt.Printf("%s: [", key) + fmt.Fprintf(cmd.OutOrStdout(), "%s: [", key) for i := 0; i < arr.Len(); i++ { if i+1 != arr.Len() { - fmt.Printf("'%v', ", arr.Index(i).Interface()) + fmt.Fprintf(cmd.OutOrStdout(), "'%v', ", arr.Index(i).Interface()) } else { - fmt.Printf("'%v'", arr.Index(i).Interface()) + fmt.Fprintf(cmd.OutOrStdout(), "'%v'", arr.Index(i).Interface()) } } - fmt.Printf("]\n") + fmt.Fprintf(cmd.OutOrStdout(), "]\n") case reflect.Map: res2B, _ := json.Marshal(value) - fmt.Printf("%s: %s\n", key, string(res2B)) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %s\n", key, string(res2B)) default: - fmt.Printf("%s: %s\n", key, value) + fmt.Fprintf(cmd.OutOrStdout(), "%s: %s\n", key, value) } } } diff --git a/cmd/validateAutoinstalls.go b/cmd/validateAutoinstalls.go index ed3656f..8d88223 100644 --- a/cmd/validateAutoinstalls.go +++ b/cmd/validateAutoinstalls.go @@ -20,7 +20,7 @@ var validateAutoinstallsCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("Event ID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) return nil }, } diff --git a/cmd/version.go b/cmd/version.go index 29c4705..0177cea 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -27,6 +27,11 @@ var versionCmd = &cobra.Command{ fmt.Printf(" build time: %s\n", version.Builddate) fmt.Printf(" cli: %s\n", cliVersion) fmt.Printf(" client: %s\n", clientVersion) + fmt.Fprintf(cmd.OutOrStdout(), "Cobbler %s\n", version.Version) + fmt.Fprintf(cmd.OutOrStdout(), " source: %s, %s\n", version.Gitstamp, version.Gitdate) + fmt.Fprintf(cmd.OutOrStdout(), " build time: %s\n", version.Builddate) + fmt.Fprintf(cmd.OutOrStdout(), " cli: %s\n", cliVersion) + fmt.Fprintf(cmd.OutOrStdout(), " client: %s\n", clientVersion) }, } From a321a26fadecbda2d96e7a10e21cee025a7a0db8 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Wed, 30 Oct 2024 11:50:59 +0100 Subject: [PATCH 02/17] Make generateCobblerClient() return an error This is so we can exit the CLI once a connection to Cobbler couldn't be successfully established. --- cmd/aclsetup.go | 5 ++- cmd/buildiso.go | 5 ++- cmd/distro.go | 42 +++++++++++++++----- cmd/event.go | 15 ++++++-- cmd/file.go | 46 +++++++++++++++++----- cmd/hardlink.go | 6 ++- cmd/image.go | 45 +++++++++++++++++----- cmd/import.go | 6 ++- cmd/list.go | 6 ++- cmd/menu.go | 49 ++++++++++++++++++----- cmd/mgmtclass.go | 46 +++++++++++++++++----- cmd/mkloaders.go | 6 ++- cmd/package.go | 48 ++++++++++++++++++----- cmd/profile.go | 57 +++++++++++++++++++++------ cmd/replicate.go | 6 ++- cmd/repo.go | 52 ++++++++++++++++++++----- cmd/report.go | 6 ++- cmd/reposync.go | 6 ++- cmd/root.go | 7 ++-- cmd/setting.go | 11 +++++- cmd/signature.go | 22 ++++++++--- cmd/sync.go | 6 ++- cmd/system.go | 77 +++++++++++++++++++++++++++++-------- cmd/validateAutoinstalls.go | 6 ++- cmd/version.go | 15 ++++---- 25 files changed, 474 insertions(+), 122 deletions(-) diff --git a/cmd/aclsetup.go b/cmd/aclsetup.go index bca561b..01574aa 100644 --- a/cmd/aclsetup.go +++ b/cmd/aclsetup.go @@ -17,7 +17,10 @@ var aclsetupCmd = &cobra.Command{ Long: "Configures users/groups to run the Cobbler CLI as non-root.", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } addUserOption, err := cmd.Flags().GetString("adduser") if err != nil { return err diff --git a/cmd/buildiso.go b/cmd/buildiso.go index 451226e..14d5568 100644 --- a/cmd/buildiso.go +++ b/cmd/buildiso.go @@ -16,7 +16,10 @@ var buildisoCmd = &cobra.Command{ Short: "Build an ISO", Long: "Build all profiles into a bootable CD image. All flags are optional.", RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } isoOption, err := cmd.Flags().GetString("iso") if err != nil { return err diff --git a/cmd/distro.go b/cmd/distro.go index 4c23a74..35f691e 100644 --- a/cmd/distro.go +++ b/cmd/distro.go @@ -331,9 +331,11 @@ var distroAddCmd = &cobra.Command{ Short: "add distribution", Long: `Adds a distribution.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } newDistro := cobbler.NewDistro() - var err error // internal fields (ctime, mtime, depth, uid, source-repos, tree-build-time) cannot be modified newDistro.Name, err = cmd.Flags().GetString("name") @@ -360,7 +362,10 @@ var distroCopyCmd = &cobra.Command{ Short: "copy distribution", Long: `Copies a distribution.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } dname, err := cmd.Flags().GetString("name") if err != nil { return err @@ -397,7 +402,10 @@ var distroEditCmd = &cobra.Command{ Short: "edit distribution", Long: `Edits a distribution.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // find distro through its name dname, err := cmd.Flags().GetString("name") @@ -434,7 +442,10 @@ var distroFindCmd = &cobra.Command{ Short: "find distribution", Long: `Finds a given distribution.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } return FindItemNames(cmd, args, "distro") }, } @@ -444,7 +455,10 @@ var distroListCmd = &cobra.Command{ Short: "list all distributions", Long: `Lists all available distributions.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } distroNames, err := Client.ListDistroNames() if err != nil { return err @@ -459,7 +473,10 @@ var distroRemoveCmd = &cobra.Command{ Short: "remove distribution", Long: `Removes a given distribution.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } dname, err := cmd.Flags().GetString("name") if err != nil { @@ -478,7 +495,10 @@ var distroRenameCmd = &cobra.Command{ Short: "rename distribution", Long: `Renames a given distribution.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get the name and newname flags distroName, err := cmd.Flags().GetString("name") @@ -532,7 +552,11 @@ var distroReportCmd = &cobra.Command{ Short: "list all distributions in detail", Long: `Shows detailed information about all distributions.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/event.go b/cmd/event.go index faa29e1..b0affed 100644 --- a/cmd/event.go +++ b/cmd/event.go @@ -21,7 +21,10 @@ var eventCmd = &cobra.Command{ var eventStatusCmd = &cobra.Command{ Use: "status", RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } eventId, err := cmd.Flags().GetString("event-id") if err != nil { @@ -40,7 +43,10 @@ var eventStatusCmd = &cobra.Command{ var eventListCmd = &cobra.Command{ Use: "list", RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } user, err := cmd.Flags().GetString("user") if err != nil { @@ -81,7 +87,10 @@ var eventListCmd = &cobra.Command{ var eventLogCmd = &cobra.Command{ Use: "log", RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } eventId, err := cmd.Flags().GetString("event-id") if err != nil { diff --git a/cmd/file.go b/cmd/file.go index 2180ca5..1a641c0 100644 --- a/cmd/file.go +++ b/cmd/file.go @@ -123,9 +123,12 @@ var fileAddCmd = &cobra.Command{ Short: "add file", Long: `Adds a file.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + newFile := cobbler.NewFile() - var err error // Get special name flag newFile.Name, err = cmd.Flags().GetString("name") @@ -152,7 +155,10 @@ var fileCopyCmd = &cobra.Command{ Short: "copy file", Long: `Copies a file.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get special name and newname flags fileName, err := cmd.Flags().GetString("name") @@ -190,7 +196,10 @@ var fileEditCmd = &cobra.Command{ Short: "edit file", Long: `Edits a file.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get the file name fileName, err := cmd.Flags().GetString("name") @@ -218,7 +227,11 @@ var fileFindCmd = &cobra.Command{ Short: "find file", Long: `Finds a given file.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "file") }, } @@ -228,7 +241,11 @@ var fileListCmd = &cobra.Command{ Short: "list all files", Long: `Lists all available files.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + fileNames, err := Client.ListFileNames() if err != nil { return err @@ -243,7 +260,11 @@ var fileRemoveCmd = &cobra.Command{ Short: "remove file", Long: `Removes a given file.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return RemoveItemRecursive(cmd, args, "file") }, } @@ -253,7 +274,10 @@ var fileRenameCmd = &cobra.Command{ Short: "rename file", Long: `Renames a given file.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get the special name and newname flags fileName, err := cmd.Flags().GetString("name") @@ -307,7 +331,11 @@ var fileReportCmd = &cobra.Command{ Short: "list all files in detail", Long: `Shows detailed information about all files.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/hardlink.go b/cmd/hardlink.go index 0b2deb2..b4e7e3f 100644 --- a/cmd/hardlink.go +++ b/cmd/hardlink.go @@ -15,7 +15,11 @@ var hardlinkCmd = &cobra.Command{ Short: "Hardlink files", Long: "Hardlink all files where it is possible to improve performance.", RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + eventId, err := Client.BackgroundHardlink() if err != nil { return err diff --git a/cmd/image.go b/cmd/image.go index 6cad80f..68121c9 100644 --- a/cmd/image.go +++ b/cmd/image.go @@ -363,9 +363,12 @@ var imageAddCmd = &cobra.Command{ Short: "add image", Long: `Adds a image.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + newImage := cobbler.NewImage() - var err error newImage.Name, err = cmd.Flags().GetString("name") if err != nil { return err @@ -390,7 +393,10 @@ var imageCopyCmd = &cobra.Command{ Short: "copy image", Long: `Copies a image.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } imageName, err := cmd.Flags().GetString("name") if err != nil { @@ -427,7 +433,10 @@ var imageEditCmd = &cobra.Command{ Short: "edit image", Long: `Edits a image.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } imageName, err := cmd.Flags().GetString("name") if err != nil { @@ -452,7 +461,10 @@ var imageFindCmd = &cobra.Command{ Short: "find image", Long: `Finds a given image.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } return FindItemNames(cmd, args, "image") }, } @@ -462,7 +474,11 @@ var imageListCmd = &cobra.Command{ Short: "list all images", Long: `Lists all available images.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + imageNames, err := Client.ListImageNames() if err != nil { return err @@ -477,7 +493,11 @@ var imageRemoveCmd = &cobra.Command{ Short: "remove image", Long: `Removes a given image.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return RemoveItemRecursive(cmd, args, "image") }, } @@ -487,7 +507,10 @@ var imageRenameCmd = &cobra.Command{ Short: "rename image", Long: `Renames a given image.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } imageName, err := cmd.Flags().GetString("name") if err != nil { @@ -536,7 +559,11 @@ var imageReportCmd = &cobra.Command{ Short: "list all images in detail", Long: `Shows detailed information about all images.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/import.go b/cmd/import.go index bf89c71..46e7e5d 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -18,7 +18,11 @@ var importCmd = &cobra.Command{ See https://cobbler.readthedocs.io/en/latest/quickstart-guide.html#importing-your-first-distribution for more information.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + archOption, err := cmd.Flags().GetString("arch") if err != nil { return err diff --git a/cmd/list.go b/cmd/list.go index 02bc7aa..cbeb19f 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -19,7 +19,11 @@ most of the other Cobbler commands (currently: distro, profile, system, repo, im Identical to 'cobbler report'`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + distroNames, err := Client.ListDistroNames() if err != nil { return err diff --git a/cmd/menu.go b/cmd/menu.go index eb9d97e..8cca9ed 100644 --- a/cmd/menu.go +++ b/cmd/menu.go @@ -67,9 +67,12 @@ var menuAddCmd = &cobra.Command{ Short: "add menu", Long: `Adds a menu.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + newMenu := cobbler.NewMenu() - var err error // internal fields (ctime, mtime, depth, uid, source-repos, tree-build-time) cannot be modified newMenu.Name, err = cmd.Flags().GetString("name") @@ -96,7 +99,11 @@ var menuCopyCmd = &cobra.Command{ Short: "copy menu", Long: `Copies a menu.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + menuName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -131,7 +138,11 @@ var menuEditCmd = &cobra.Command{ Short: "edit menu", Long: `Edits a menu.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + menuName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -154,7 +165,11 @@ var menuFindCmd = &cobra.Command{ Short: "find menu", Long: `Finds a given menu.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "menu") }, } @@ -164,7 +179,11 @@ var menuListCmd = &cobra.Command{ Short: "list all menus", Long: `Lists all available menus.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + menuNames, err := Client.ListMenuNames() if err != nil { return err @@ -179,7 +198,11 @@ var menuRemoveCmd = &cobra.Command{ Short: "remove menu", Long: `Removes a given menu.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return RemoveItemRecursive(cmd, args, "menu") }, } @@ -189,7 +212,11 @@ var menuRenameCmd = &cobra.Command{ Short: "rename menu", Long: `Renames a given menu.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + menuName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -236,7 +263,11 @@ var menuReportCmd = &cobra.Command{ Short: "list all menus in detail", Long: `Shows detailed information about all menus.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/mgmtclass.go b/cmd/mgmtclass.go index 9981a9d..d047d7d 100644 --- a/cmd/mgmtclass.go +++ b/cmd/mgmtclass.go @@ -118,9 +118,12 @@ var mgmtclassAddCmd = &cobra.Command{ Short: "add mgmtclass", Long: `Adds a mgmtclass.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + newMgmtClass := cobbler.NewMgmtClass() - var err error // Get special name flag newMgmtClass.Name, err = cmd.Flags().GetString("name") @@ -147,7 +150,10 @@ var mgmtclassCopyCmd = &cobra.Command{ Short: "copy mgmtclass", Long: `Copies a mgmtclass.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get special name and newname flags mgmtClassName, err := cmd.Flags().GetString("name") @@ -189,7 +195,10 @@ var mgmtclassEditCmd = &cobra.Command{ Short: "edit mgmtclass", Long: `Edits a mgmtclass.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Collect CLI flags mgmtClassName, err := cmd.Flags().GetString("name") @@ -217,7 +226,11 @@ var mgmtclassFindCmd = &cobra.Command{ Short: "find mgmtclass", Long: `Finds a given mgmtclass.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "mgmtclass") }, } @@ -227,7 +240,11 @@ var mgmtclassListCmd = &cobra.Command{ Short: "list all mgmtclasses", Long: `Lists all available mgmtclasses.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + mgmtclassNames, err := Client.ListMgmtClassNames() if err != nil { return err @@ -242,7 +259,11 @@ var mgmtclassRemoveCmd = &cobra.Command{ Short: "remove mgmtclass", Long: `Removes a given mgmtclass.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return RemoveItemRecursive(cmd, args, "mgmtclass") }, } @@ -252,7 +273,10 @@ var mgmtclassRenameCmd = &cobra.Command{ Short: "rename mgmtclass", Long: `Renames a given mgmtclass.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get the special name and newname flags mgmtClassName, err := cmd.Flags().GetString("name") @@ -306,7 +330,11 @@ var mgmtclassReportCmd = &cobra.Command{ Short: "list all mgmtclasses in detail", Long: `Shows detailed information about all mgmtclasses.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/mkloaders.go b/cmd/mkloaders.go index f0c3d38..c3ce785 100644 --- a/cmd/mkloaders.go +++ b/cmd/mkloaders.go @@ -18,7 +18,11 @@ then this also generates bootloaders for different architectures then the one of The options are configured in the Cobbler settings file.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + eventId, err := Client.BackgroundMkLoaders() if err != nil { return err diff --git a/cmd/package.go b/cmd/package.go index 84cf0a6..12941b0 100644 --- a/cmd/package.go +++ b/cmd/package.go @@ -87,9 +87,12 @@ var packageAddCmd = &cobra.Command{ Short: "add package", Long: `Adds a package.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + newPackage := cobbler.NewPackage() - var err error // internal fields (ctime, mtime, depth, uid) cannot be modified newPackage.Name, err = cmd.Flags().GetString("name") @@ -116,7 +119,11 @@ var packageCopyCmd = &cobra.Command{ Short: "copy package", Long: `Copies a package.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + // Collect CLI flags packageName, err := cmd.Flags().GetString("name") if err != nil { @@ -157,7 +164,11 @@ var packageEditCmd = &cobra.Command{ Short: "edit package", Long: `Edits a package.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + packageName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -183,7 +194,11 @@ var packageFindCmd = &cobra.Command{ Short: "find package", Long: `Finds a given package.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "package") }, } @@ -193,7 +208,11 @@ var packageListCmd = &cobra.Command{ Short: "list all packages", Long: `Lists all available packages.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + packageNames, err := Client.ListPackageNames() if err != nil { return err @@ -208,7 +227,11 @@ var packageRemoveCmd = &cobra.Command{ Short: "remove package", Long: `Removes a given package.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return RemoveItemRecursive(cmd, args, "package") }, } @@ -218,7 +241,10 @@ var packageRenameCmd = &cobra.Command{ Short: "rename package", Long: `Renames a given package.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // internal fields (ctime, mtime, depth, uid) cannot be modified packageName, err := cmd.Flags().GetString("name") @@ -272,7 +298,11 @@ var packageReportCmd = &cobra.Command{ Short: "list all packages in detail", Long: `Shows detailed information about all packages.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/profile.go b/cmd/profile.go index d30c4e9..da9c01b 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -521,10 +521,12 @@ var profileAddCmd = &cobra.Command{ Short: "add profile", Long: `Adds a profile.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } newProfile := cobbler.NewProfile() - var err error // internal fields (ctime, mtime, uid, depth, repos-enabled) cannot be modified newProfile.Name, err = cmd.Flags().GetString("name") if err != nil { @@ -548,7 +550,11 @@ var profileCopyCmd = &cobra.Command{ Short: "copy profile", Long: `Copies a profile.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + profileName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -583,7 +589,10 @@ var profileDumpVarsCmd = &cobra.Command{ Short: "dump profile variables", Long: `Prints all profile variables to stdout.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get CLI flags profileName, err := cmd.Flags().GetString("name") @@ -607,7 +616,10 @@ var profileEditCmd = &cobra.Command{ Short: "edit profile", Long: `Edits a profile.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // find profile through its name pname, err := cmd.Flags().GetString("name") @@ -633,7 +645,11 @@ var profileFindCmd = &cobra.Command{ Short: "find profile", Long: `Finds a given profile.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "profile") }, } @@ -643,7 +659,11 @@ var profileGetAutoinstallCmd = &cobra.Command{ Short: "dump autoinstall XML", Long: `Prints the autoinstall XML file of the given profile to stdout.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + profileName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -670,7 +690,11 @@ var profileListCmd = &cobra.Command{ Short: "list all profiles", Long: `Lists all available profiles.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + profileNames, err := Client.ListProfileNames() if err != nil { return err @@ -685,7 +709,10 @@ var profileRemoveCmd = &cobra.Command{ Short: "remove profile", Long: `Removes a given profile.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } pname, err := cmd.Flags().GetString("name") if err != nil { @@ -704,7 +731,11 @@ var profileRenameCmd = &cobra.Command{ Short: "rename profile", Long: `Renames a given profile.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + profileName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -752,7 +783,11 @@ var profileReportCmd = &cobra.Command{ Short: "list all profiles in detail", Long: `Shows detailed information about all profiles.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/replicate.go b/cmd/replicate.go index 993d574..11d6683 100644 --- a/cmd/replicate.go +++ b/cmd/replicate.go @@ -21,7 +21,11 @@ relevant cobbler.conf and modules.conf, as these files are not synced. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-replicate for more information.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + distrosOption, err := cmd.Flags().GetString("distros") if err != nil { return err diff --git a/cmd/repo.go b/cmd/repo.go index 1d56231..1e7ee1c 100644 --- a/cmd/repo.go +++ b/cmd/repo.go @@ -186,9 +186,12 @@ var repoAddCmd = &cobra.Command{ Short: "add repository", Long: `Adds a repository.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + newRepo := cobbler.NewRepo() - var err error // internal fields (ctime, mtime, depth, uid, parent, tree-build-time) cannot be modified newRepo.Name, err = cmd.Flags().GetString("name") @@ -215,7 +218,11 @@ var repoAutoAddCmd = &cobra.Command{ Short: "add repository automatically", Long: `Automatically adds a repository.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return Client.AutoAddRepos() }, } @@ -225,7 +232,10 @@ var repoCopyCmd = &cobra.Command{ Short: "copy repository", Long: `Copies a repository.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } repoName, err := cmd.Flags().GetString("name") if err != nil { @@ -261,7 +271,10 @@ var repoEditCmd = &cobra.Command{ Short: "edit repository", Long: `Edits a repository.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // find repo through its name rname, err := cmd.Flags().GetString("name") @@ -288,7 +301,11 @@ var repoFindCmd = &cobra.Command{ Short: "find repository", Long: `Finds a given repository.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "repo") }, } @@ -298,7 +315,11 @@ var repoListCmd = &cobra.Command{ Short: "list all repositorys", Long: `Lists all available repositories.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + repoNames, err := Client.ListRepoNames() if err != nil { return err @@ -313,7 +334,11 @@ var repoRemoveCmd = &cobra.Command{ Short: "remove repository", Long: `Removes a given repository.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return RemoveItemRecursive(cmd, args, "repo") }, } @@ -323,7 +348,10 @@ var repoRenameCmd = &cobra.Command{ Short: "rename repository", Long: `Renames a given repository.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get special name and newname flags repoName, err := cmd.Flags().GetString("name") @@ -376,7 +404,11 @@ var repoReportCmd = &cobra.Command{ Short: "list all repositorys in detail", Long: `Shows detailed information about all repositories.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/report.go b/cmd/report.go index a6bbe9e..d0aa36e 100644 --- a/cmd/report.go +++ b/cmd/report.go @@ -18,7 +18,11 @@ most of the other Cobbler commands (currently: distro, profile, system, repo, im Identical to 'cobbler list'`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + // Distro fmt.Fprintln(cmd.OutOrStdout(), "distros:") fmt.Fprintln(cmd.OutOrStdout(), "==========") diff --git a/cmd/reposync.go b/cmd/reposync.go index ae694c0..ca7e812 100644 --- a/cmd/reposync.go +++ b/cmd/reposync.go @@ -19,7 +19,11 @@ var reposyncCmd = &cobra.Command{ See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-reposync for more information.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + noFailOption, err := cmd.Flags().GetBool("no-fail") if err != nil { return err diff --git a/cmd/root.go b/cmd/root.go index 4689ee5..81beda7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -86,7 +86,7 @@ func initConfig() { } // basic connection to the Cobbler server -func generateCobblerClient() { +func generateCobblerClient() error { // the configuration is done in .cobbler.yaml conf.URL = viper.GetString("server_url") @@ -96,9 +96,10 @@ func generateCobblerClient() { Client = cobbler.NewClient(httpClient, conf) login, err := Client.Login() - if !login || err != nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Errorf("error! Failed to login: %s", err)) + if !login { + return fmt.Errorf("failed to login") } + return err } func printStructured(cmd *cobra.Command, dataStruct interface{}) { diff --git a/cmd/setting.go b/cmd/setting.go index 456b4be..95cef69 100644 --- a/cmd/setting.go +++ b/cmd/setting.go @@ -25,7 +25,10 @@ var settingEditCmd = &cobra.Command{ Short: "edit settings", Long: `Edits the settings.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } settings, err := Client.GetSettings() if err != nil { @@ -62,7 +65,11 @@ var settingReportCmd = &cobra.Command{ Short: "list settings", Long: `Prints settings to stdout.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + settings, err := Client.GetSettings() if err != nil { return err diff --git a/cmd/signature.go b/cmd/signature.go index 432a824..f90a298 100644 --- a/cmd/signature.go +++ b/cmd/signature.go @@ -26,7 +26,10 @@ var signatureReportCmd = &cobra.Command{ Short: "Report the loaded signatures", Long: `Report the loaded signatures`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get signatures signatures, err := Client.GetSignatures() @@ -74,10 +77,15 @@ var signatureUpdateCmd = &cobra.Command{ Use: "update", Short: "Update the signatures JSON file", Long: `Retrieve an up-to-date "distro_signatures.json" file from the server-side configured webservice.`, - Run: func(cmd *cobra.Command, args []string) { - generateCobblerClient() + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + eventId, _ := Client.BackgroundSignatureUpdate() fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil }, } @@ -85,10 +93,14 @@ var signatureReloadCmd = &cobra.Command{ Use: "reload", Short: "Reloads signatures", Long: `Reloads signatures from the - on the server - local "distro_signatures.json" file.`, - Run: func(cmd *cobra.Command, args []string) { - generateCobblerClient() + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } fmt.Fprintln(cmd.OutOrStdout(), "This functionality cannot be used in the new CLI until https://github.com/cobbler/cobbler/issues/3791 is implemented!") + return nil }, } diff --git a/cmd/sync.go b/cmd/sync.go index 6a7090b..aa745d9 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -20,7 +20,11 @@ changed behind the scenes. It brings the filesystem up to date with the configur See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-sync for more information.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + dhcpOption, err := cmd.Flags().GetBool("dhcp") if err != nil { return err diff --git a/cmd/system.go b/cmd/system.go index 31efe1e..9a238de 100644 --- a/cmd/system.go +++ b/cmd/system.go @@ -779,10 +779,12 @@ var systemAddCmd = &cobra.Command{ Short: "add system", Long: `Adds a system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } newSystem := cobbler.NewSystem() - var err error // internal fields (ctime, mtime, depth, uid, repos-enabled, ipv6-autoconfiguration) cannot be modified newSystem.Name, err = cmd.Flags().GetString("name") @@ -809,7 +811,11 @@ var systemCopyCmd = &cobra.Command{ Short: "copy system", Long: `Copies a system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + systemName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -856,7 +862,10 @@ var systemDumpVarsCmd = &cobra.Command{ Short: "dump system variables", Long: `Prints all system variables to stdout.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get CLI flags systemName, err := cmd.Flags().GetString("name") @@ -880,7 +889,10 @@ var systemEditCmd = &cobra.Command{ Short: "edit system", Long: `Edits a system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // find profile through its name systemName, err := cmd.Flags().GetString("name") @@ -917,7 +929,11 @@ var systemFindCmd = &cobra.Command{ Short: "find system", Long: `Finds a given system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "system") }, } @@ -927,7 +943,11 @@ var systemGetAutoinstallCmd = &cobra.Command{ Short: "dump autoinstall XML", Long: `Prints the autoinstall XML file of the given system to stdout.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + systemName, err := cmd.Flags().GetString("name") if err != nil { return err @@ -954,7 +974,11 @@ var systemListCmd = &cobra.Command{ Short: "list all systems", Long: `Lists all available systems.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + systemNames, err := Client.ListSystemNames() if err != nil { return err @@ -969,7 +993,10 @@ var systemPowerOffCmd = &cobra.Command{ Short: "power off system", Long: `Powers off the selected system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get flags systemName, err := cmd.Flags().GetString("name") @@ -992,7 +1019,10 @@ var systemPowerOnCmd = &cobra.Command{ Short: "power on system", Long: `Powers on the selected system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get flags systemName, err := cmd.Flags().GetString("name") @@ -1015,7 +1045,10 @@ var systemPowerStatusCmd = &cobra.Command{ Short: "Power status of the system", Long: `Querys the power status of the selected system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get flags systemName, err := cmd.Flags().GetString("name") @@ -1038,7 +1071,10 @@ var systemRebootCmd = &cobra.Command{ Short: "reboot system", Long: `Reboots the selected system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get flags systemName, err := cmd.Flags().GetString("name") @@ -1061,7 +1097,11 @@ var systemRemoveCmd = &cobra.Command{ Short: "remove system", Long: `Removes a given system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + return RemoveItemRecursive(cmd, args, "system") }, } @@ -1071,7 +1111,10 @@ var systemRenameCmd = &cobra.Command{ Short: "rename system", Long: `Renames a given system.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } // Get flags systemName, err := cmd.Flags().GetString("name") @@ -1131,7 +1174,11 @@ var systemReportCmd = &cobra.Command{ Short: "list all systems in detail", Long: `Shows detailed information about all systems.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + name, err := cmd.Flags().GetString("name") if err != nil { return err diff --git a/cmd/validateAutoinstalls.go b/cmd/validateAutoinstalls.go index 8d88223..e2c2a5c 100644 --- a/cmd/validateAutoinstalls.go +++ b/cmd/validateAutoinstalls.go @@ -15,7 +15,11 @@ var validateAutoinstallsCmd = &cobra.Command{ Short: "Autoinstall validation", Long: `Validates the autoinstall files.`, RunE: func(cmd *cobra.Command, args []string) error { - generateCobblerClient() + err := generateCobblerClient() + if err != nil { + return err + } + eventId, err := Client.BackgroundValidateAutoinstallFiles() if err != nil { return err diff --git a/cmd/version.go b/cmd/version.go index 0177cea..631cae2 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -15,23 +15,22 @@ var versionCmd = &cobra.Command{ Use: "version", Short: "Print the Cobbler version", Long: `Shows the Cobbler server version.`, - Run: func(cmd *cobra.Command, args []string) { - generateCobblerClient() + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } version, err := Client.ExtendedVersion() if err != nil { - fmt.Println(err) + return err } clientVersion, cliVersion, _ := getClientVersion() - fmt.Printf("Cobbler %s\n", version.Version) - fmt.Printf(" source: %s, %s\n", version.Gitstamp, version.Gitdate) - fmt.Printf(" build time: %s\n", version.Builddate) - fmt.Printf(" cli: %s\n", cliVersion) - fmt.Printf(" client: %s\n", clientVersion) fmt.Fprintf(cmd.OutOrStdout(), "Cobbler %s\n", version.Version) fmt.Fprintf(cmd.OutOrStdout(), " source: %s, %s\n", version.Gitstamp, version.Gitdate) fmt.Fprintf(cmd.OutOrStdout(), " build time: %s\n", version.Builddate) fmt.Fprintf(cmd.OutOrStdout(), " cli: %s\n", cliVersion) fmt.Fprintf(cmd.OutOrStdout(), " client: %s\n", clientVersion) + return nil }, } From 86697dcf572d019bd1f4d69cab9878641dbfd491 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Wed, 30 Oct 2024 16:37:23 +0100 Subject: [PATCH 03/17] Use NewCmd() methods to replace global variables This is needed to test our code easier and to move the argument definition closer to the actual command logic. --- cmd/aclsetup.go | 89 ++-- cmd/buildiso.go | 147 +++--- cmd/distro.go | 575 ++++++++++++----------- cmd/event.go | 193 ++++---- cmd/file.go | 505 ++++++++++---------- cmd/hardlink.go | 41 +- cmd/image.go | 497 ++++++++++---------- cmd/import.go | 127 +++-- cmd/list.go | 121 +++-- cmd/menu.go | 473 ++++++++++--------- cmd/mgmtclass.go | 527 +++++++++++---------- cmd/mkloaders.go | 41 +- cmd/package.go | 507 ++++++++++---------- cmd/profile.go | 639 ++++++++++++------------- cmd/replicate.go | 187 ++++---- cmd/repo.go | 545 +++++++++++----------- cmd/report.go | 247 +++++----- cmd/reposync.go | 81 ++-- cmd/root.go | 64 ++- cmd/setting.go | 145 +++--- cmd/signature.go | 178 +++---- cmd/sync.go | 99 ++-- cmd/system.go | 907 ++++++++++++++++++------------------ cmd/validateAutoinstalls.go | 41 +- cmd/version.go | 51 +- 25 files changed, 3583 insertions(+), 3444 deletions(-) diff --git a/cmd/aclsetup.go b/cmd/aclsetup.go index 01574aa..0027c10 100644 --- a/cmd/aclsetup.go +++ b/cmd/aclsetup.go @@ -10,54 +10,51 @@ import ( "github.com/spf13/cobra" ) -// aclsetupCmd represents the aclsetup command -var aclsetupCmd = &cobra.Command{ - Use: "aclsetup", - Short: "Adjust the access control list", - Long: "Configures users/groups to run the Cobbler CLI as non-root.", - Args: cobra.MinimumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - addUserOption, err := cmd.Flags().GetString("adduser") - if err != nil { - return err - } - addGroupOption, err := cmd.Flags().GetString("addgroup") - if err != nil { - return err - } - removeUserOption, err := cmd.Flags().GetString("removeuser") - if err != nil { - return err - } - removeGroupOption, err := cmd.Flags().GetString("removegroup") - if err != nil { - return err - } - aclSetupOptions := cobblerclient.AclSetupOptions{ - AddUser: addUserOption, - AddGroup: addGroupOption, - RemoveUser: removeUserOption, - RemoveGroup: removeGroupOption, - } - eventId, err := Client.BackgroundAclSetup(aclSetupOptions) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "Event ID: ", eventId) - return nil - }, -} - -func init() { - rootCmd.AddCommand(aclsetupCmd) - - //local flags +// NewAclSetupCmd builds a new command that represent the aclsetup action. +func NewAclSetupCmd() *cobra.Command { + aclsetupCmd := &cobra.Command{ + Use: "aclsetup", + Short: "Adjust the access control list", + Long: "Configures users/groups to run the Cobbler CLI as non-root.", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + addUserOption, err := cmd.Flags().GetString("adduser") + if err != nil { + return err + } + addGroupOption, err := cmd.Flags().GetString("addgroup") + if err != nil { + return err + } + removeUserOption, err := cmd.Flags().GetString("removeuser") + if err != nil { + return err + } + removeGroupOption, err := cmd.Flags().GetString("removegroup") + if err != nil { + return err + } + aclSetupOptions := cobblerclient.AclSetupOptions{ + AddUser: addUserOption, + AddGroup: addGroupOption, + RemoveUser: removeUserOption, + RemoveGroup: removeGroupOption, + } + eventId, err := Client.BackgroundAclSetup(aclSetupOptions) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "Event ID: ", eventId) + return nil + }, + } aclsetupCmd.Flags().String("adduser", "", "give acls to this user") aclsetupCmd.Flags().String("addgroup", "", "give acls to this group") aclsetupCmd.Flags().String("removeuser", "", "remove acls from this user") aclsetupCmd.Flags().String("removegroup", "", "remove acls from this user") + return aclsetupCmd } diff --git a/cmd/buildiso.go b/cmd/buildiso.go index 14d5568..8a5d924 100644 --- a/cmd/buildiso.go +++ b/cmd/buildiso.go @@ -10,81 +10,77 @@ import ( "github.com/spf13/cobra" ) -// buildisoCmd represents the buildiso command -var buildisoCmd = &cobra.Command{ - Use: "buildiso", - Short: "Build an ISO", - Long: "Build all profiles into a bootable CD image. All flags are optional.", - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - isoOption, err := cmd.Flags().GetString("iso") - if err != nil { - return err - } - distroOption, err := cmd.Flags().GetString("distro") - if err != nil { - return err - } - xorrisofsOption, err := cmd.Flags().GetString("mkisofs-opts") - if err != nil { - return err - } - profilesOption, err := cmd.Flags().GetStringSlice("profiles") - if err != nil { - return err - } - sourceOption, err := cmd.Flags().GetString("source") - if err != nil { - return err - } - systemsOption, err := cmd.Flags().GetStringSlice("systems") - if err != nil { - return err - } - tempdirOption, err := cmd.Flags().GetString("tempdir") - if err != nil { - return err - } - standaloneOption, err := cmd.Flags().GetBool("standalone") - if err != nil { - return err - } - excludeDnsOption, err := cmd.Flags().GetBool("exclude-dns") - if err != nil { - return err - } - airgappedOption, err := cmd.Flags().GetBool("airgapped") - if err != nil { - return err - } - buildisoOptions := cobblerclient.BuildisoOptions{ - Iso: isoOption, - Profiles: profilesOption, - Systems: systemsOption, - BuildisoDir: tempdirOption, - Distro: distroOption, - Standalone: standaloneOption, - Airgapped: airgappedOption, - Source: sourceOption, - ExcludeDns: excludeDnsOption, - XorrisofsOpts: xorrisofsOption, - } - eventId, err := Client.BackgroundBuildiso(buildisoOptions) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) - return nil - }, -} - -func init() { - rootCmd.AddCommand(buildisoCmd) - - //local flags +// NewBuildisoCmd builds a new command that represents the buildiso action +func NewBuildisoCmd() *cobra.Command { + buildisoCmd := &cobra.Command{ + Use: "buildiso", + Short: "Build an ISO", + Long: "Build all profiles into a bootable CD image. All flags are optional.", + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + isoOption, err := cmd.Flags().GetString("iso") + if err != nil { + return err + } + distroOption, err := cmd.Flags().GetString("distro") + if err != nil { + return err + } + xorrisofsOption, err := cmd.Flags().GetString("mkisofs-opts") + if err != nil { + return err + } + profilesOption, err := cmd.Flags().GetStringSlice("profiles") + if err != nil { + return err + } + sourceOption, err := cmd.Flags().GetString("source") + if err != nil { + return err + } + systemsOption, err := cmd.Flags().GetStringSlice("systems") + if err != nil { + return err + } + tempdirOption, err := cmd.Flags().GetString("tempdir") + if err != nil { + return err + } + standaloneOption, err := cmd.Flags().GetBool("standalone") + if err != nil { + return err + } + excludeDnsOption, err := cmd.Flags().GetBool("exclude-dns") + if err != nil { + return err + } + airgappedOption, err := cmd.Flags().GetBool("airgapped") + if err != nil { + return err + } + buildisoOptions := cobblerclient.BuildisoOptions{ + Iso: isoOption, + Profiles: profilesOption, + Systems: systemsOption, + BuildisoDir: tempdirOption, + Distro: distroOption, + Standalone: standaloneOption, + Airgapped: airgappedOption, + Source: sourceOption, + ExcludeDns: excludeDnsOption, + XorrisofsOpts: xorrisofsOption, + } + eventId, err := Client.BackgroundBuildiso(buildisoOptions) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil + }, + } buildisoCmd.Flags().Bool("airgapped", false, "creates a standalone ISO with all distro and repo files for disconnected system installation") buildisoCmd.Flags().String("distro", "", "used with --standalone and --airgapped to create a distro-based ISO including all associated profiles/systems") buildisoCmd.Flags().Bool("exclude-dns", false, "prevents addition of name server addresses to the kernel boot options") @@ -95,4 +91,5 @@ func init() { buildisoCmd.Flags().Bool("standalone", false, "creates a standalone ISO with all required distro files, but without any added repos") buildisoCmd.Flags().StringSlice("systems", []string{}, "use these systems only") buildisoCmd.Flags().String("tempdir", "", "working directory") + return buildisoCmd } diff --git a/cmd/distro.go b/cmd/distro.go index 35f691e..edd908d 100644 --- a/cmd/distro.go +++ b/cmd/distro.go @@ -315,277 +315,91 @@ func updateDistroFromFlags(cmd *cobra.Command, distro *cobbler.Distro) error { return err } -// distroCmd represents the distro command -var distroCmd = &cobra.Command{ - Use: "distro", - Short: "Distribution management", - Long: `Let you manage distributions. +// NewDistroCmd builds a new command that represents the distro action +func NewDistroCmd() (*cobra.Command, error) { + distroCmd := &cobra.Command{ + Use: "distro", + Short: "Distribution management", + Long: `Let you manage distributions. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-distro for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, -} - -var distroAddCmd = &cobra.Command{ - Use: "add", - Short: "add distribution", - Long: `Adds a distribution.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - newDistro := cobbler.NewDistro() - - // internal fields (ctime, mtime, depth, uid, source-repos, tree-build-time) cannot be modified - newDistro.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - // Update distro in-memory - err = updateDistroFromFlags(cmd, &newDistro) - if err != nil { - return err - } - // Now create the distro via XML-RPC - distro, err := Client.CreateDistro(newDistro) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Distro %s created\n", distro.Name) - return nil - }, -} - -var distroCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy distribution", - Long: `Copies a distribution.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - dname, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - distroNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - dhandle, err := Client.GetDistroHandle(dname) - if err != nil { - return err - } - err = Client.CopyDistro(dhandle, distroNewName) - if err != nil { - return err - } - newDistro, err := Client.GetDistro(distroNewName, false, false) - if err != nil { - return err - } - // Update distro in-memory - err = updateDistroFromFlags(cmd, newDistro) - if err != nil { - return err - } - // Update the distro via XML-RPC - return Client.UpdateDistro(newDistro) - }, -} - -var distroEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit distribution", - Long: `Edits a distribution.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // find distro through its name - dname, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - // Get distro from the API - updateDistro, err := Client.GetDistro(dname, false, false) - if err != nil { - return err - } - // Update distro in-memory - err = updateDistroFromFlags(cmd, updateDistro) - if err != nil { - return err - } - if updateDistro.Meta.IsDirty { - updateDistro, err = Client.GetDistro( - updateDistro.Name, - updateDistro.Meta.IsFlattened, - updateDistro.Meta.IsResolved, - ) - if err != nil { - return err - } - } - // Now update distro via XML-RPC - return Client.UpdateDistro(updateDistro) - }, -} - -var distroFindCmd = &cobra.Command{ - Use: "find", - Short: "find distribution", - Long: `Finds a given distribution.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - return FindItemNames(cmd, args, "distro") - }, -} - -var distroListCmd = &cobra.Command{ - Use: "list", - Short: "list all distributions", - Long: `Lists all available distributions.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - distroNames, err := Client.ListDistroNames() - if err != nil { - return err - } - listItems(cmd, "distros", distroNames) - return nil - }, -} - -var distroRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove distribution", - Long: `Removes a given distribution.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - dname, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - recursiveDelete, err := cmd.Flags().GetBool("recursive") - if err != nil { - return err - } - return Client.DeleteDistroRecursive(dname, recursiveDelete) - }, -} - -var distroRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename distribution", - Long: `Renames a given distribution.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get the name and newname flags - distroName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - distroNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - // Get the distro API handle - distroHandle, err := Client.GetDistroHandle(distroName) - if err != nil { - return err - } - // Perform the rename operation server-side - err = Client.RenameDistro(distroHandle, distroNewName) - if err != nil { - return err - } - // Retrieve the renamed distro from the API - newDistro, err := Client.GetDistro(distroNewName, false, false) - if err != nil { - return err - } - // Now edit the distro in-memory - err = updateDistroFromFlags(cmd, newDistro) - if err != nil { - return err - } - // Now update the distro via XML-RPC - return Client.UpdateDistro(newDistro) - }, -} - -func reportDistros(cmd *cobra.Command, distroNames []string) error { - for _, itemName := range distroNames { - distro, err := Client.GetDistro(itemName, false, false) - if err != nil { - return err - } - printStructured(cmd, distro) - fmt.Fprintln(cmd.OutOrStdout(), "") + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + distroAddCmd, err := NewDistroAddCmd() + if err != nil { + return nil, err } - return nil -} - -var distroReportCmd = &cobra.Command{ - Use: "report", - Short: "list all distributions in detail", - Long: `Shows detailed information about all distributions.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListDistroNames() - if err != nil { - return err - } - } else { - itemNames = append(itemNames, name) - } - return reportDistros(cmd, itemNames) - }, -} - -func init() { - rootCmd.AddCommand(distroCmd) distroCmd.AddCommand(distroAddCmd) + distroCopyCmd, err := NewDistroCopyCmd() + if err != nil { + return nil, err + } distroCmd.AddCommand(distroCopyCmd) + distroEditCmd, err := NewDistroEditCmd() + if err != nil { + return nil, err + } distroCmd.AddCommand(distroEditCmd) + distroFindCmd, err := NewDistroFindCmd() + if err != nil { + return nil, err + } distroCmd.AddCommand(distroFindCmd) + distroListCmd, err := NewDistroListCmd() + if err != nil { + return nil, err + } distroCmd.AddCommand(distroListCmd) + distroRemoveCmd, err := NewDistroRemoveCmd() + if err != nil { + return nil, err + } distroCmd.AddCommand(distroRemoveCmd) + distroRenameCmd, err := NewDistroRenameCmd() + if err != nil { + return nil, err + } distroCmd.AddCommand(distroRenameCmd) + distroReportCmd, err := NewDistroReportCmd() + if err != nil { + return nil, err + } distroCmd.AddCommand(distroReportCmd) + return distroCmd, nil +} - // local flags for distro add +func NewDistroAddCmd() (*cobra.Command, error) { + distroAddCmd := &cobra.Command{ + Use: "add", + Short: "add distribution", + Long: `Adds a distribution.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + newDistro := cobbler.NewDistro() + + // internal fields (ctime, mtime, depth, uid, source-repos, tree-build-time) cannot be modified + newDistro.Name, err = cmd.Flags().GetString("name") + if err != nil { + return err + } + // Update distro in-memory + err = updateDistroFromFlags(cmd, &newDistro) + if err != nil { + return err + } + // Now create the distro via XML-RPC + distro, err := Client.CreateDistro(newDistro) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Distro %s created\n", distro.Name) + return nil + }, + } addCommonArgs(distroAddCmd) addStringFlags(distroAddCmd, distroStringFlagMetadata) addStringSliceFlags(distroAddCmd, distroStringSliceFlagMetadata) @@ -593,25 +407,121 @@ func init() { // Required Flags err := distroAddCmd.MarkFlagRequired("name") if err != nil { - panic(err) + return nil, err } + return distroAddCmd, nil +} + +func NewDistroCopyCmd() (*cobra.Command, error) { + distroCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy distribution", + Long: `Copies a distribution.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + dname, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + distroNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // local flags for distro copy + dhandle, err := Client.GetDistroHandle(dname) + if err != nil { + return err + } + err = Client.CopyDistro(dhandle, distroNewName) + if err != nil { + return err + } + newDistro, err := Client.GetDistro(distroNewName, false, false) + if err != nil { + return err + } + // Update distro in-memory + err = updateDistroFromFlags(cmd, newDistro) + if err != nil { + return err + } + // Update the distro via XML-RPC + return Client.UpdateDistro(newDistro) + }, + } addCommonArgs(distroCopyCmd) addStringFlags(distroCopyCmd, distroStringFlagMetadata) addStringSliceFlags(distroCopyCmd, distroStringSliceFlagMetadata) addMapFlags(distroCopyCmd, distroMapFlagMetadata) distroCopyCmd.Flags().String("newname", "", "the new distro name") distroCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return distroCopyCmd, nil +} - // local flags for distro edit +func NewDistroEditCmd() (*cobra.Command, error) { + distroEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit distribution", + Long: `Edits a distribution.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // find distro through its name + dname, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + // Get distro from the API + updateDistro, err := Client.GetDistro(dname, false, false) + if err != nil { + return err + } + // Update distro in-memory + err = updateDistroFromFlags(cmd, updateDistro) + if err != nil { + return err + } + if updateDistro.Meta.IsDirty { + updateDistro, err = Client.GetDistro( + updateDistro.Name, + updateDistro.Meta.IsFlattened, + updateDistro.Meta.IsResolved, + ) + if err != nil { + return err + } + } + // Now update distro via XML-RPC + return Client.UpdateDistro(updateDistro) + }, + } addCommonArgs(distroEditCmd) addStringFlags(distroEditCmd, distroStringFlagMetadata) addStringSliceFlags(distroEditCmd, distroStringSliceFlagMetadata) addMapFlags(distroEditCmd, distroMapFlagMetadata) distroEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return distroEditCmd, nil +} - // local flags for distro find +func NewDistroFindCmd() (*cobra.Command, error) { + distroFindCmd := &cobra.Command{ + Use: "find", + Short: "find distribution", + Long: `Finds a given distribution.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "distro") + }, + } addCommonArgs(distroFindCmd) addStringFlags(distroFindCmd, distroStringFlagMetadata) addStringSliceFlags(distroFindCmd, distroStringSliceFlagMetadata) @@ -621,19 +531,150 @@ func init() { addFloatFlags(distroFindCmd, findFloatFlagMetadata) distroFindCmd.Flags().String("source-repos", "", "source repositories") distroFindCmd.Flags().String("tree-build-time", "", "tree build time") + return distroFindCmd, nil +} + +func NewDistroListCmd() (*cobra.Command, error) { + distroListCmd := &cobra.Command{ + Use: "list", + Short: "list all distributions", + Long: `Lists all available distributions.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + distroNames, err := Client.ListDistroNames() + if err != nil { + return err + } + listItems(cmd, "distros", distroNames) + return nil + }, + } + return distroListCmd, nil +} + +func NewDistroRemoveCmd() (*cobra.Command, error) { + distroRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove distribution", + Long: `Removes a given distribution.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for distro remove + dname, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + recursiveDelete, err := cmd.Flags().GetBool("recursive") + if err != nil { + return err + } + return Client.DeleteDistroRecursive(dname, recursiveDelete) + }, + } distroRemoveCmd.Flags().String("name", "", "the distro name") distroRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return distroRemoveCmd, nil +} + +func NewDistroRenameCmd() (*cobra.Command, error) { + distroRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename distribution", + Long: `Renames a given distribution.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // Get the name and newname flags + distroName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + distroNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // local flags for distro rename + // Get the distro API handle + distroHandle, err := Client.GetDistroHandle(distroName) + if err != nil { + return err + } + // Perform the rename operation server-side + err = Client.RenameDistro(distroHandle, distroNewName) + if err != nil { + return err + } + // Retrieve the renamed distro from the API + newDistro, err := Client.GetDistro(distroNewName, false, false) + if err != nil { + return err + } + // Now edit the distro in-memory + err = updateDistroFromFlags(cmd, newDistro) + if err != nil { + return err + } + // Now update the distro via XML-RPC + return Client.UpdateDistro(newDistro) + }, + } addCommonArgs(distroRenameCmd) addStringFlags(distroRenameCmd, distroStringFlagMetadata) addStringSliceFlags(distroRenameCmd, distroStringSliceFlagMetadata) addMapFlags(distroRenameCmd, distroMapFlagMetadata) distroRenameCmd.Flags().String("newname", "", "the new distro name") distroRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return distroRenameCmd, nil +} - // local flags for distro report +func reportDistros(cmd *cobra.Command, distroNames []string) error { + for _, itemName := range distroNames { + distro, err := Client.GetDistro(itemName, false, false) + if err != nil { + return err + } + printStructured(cmd, distro) + fmt.Fprintln(cmd.OutOrStdout(), "") + } + return nil +} + +func NewDistroReportCmd() (*cobra.Command, error) { + distroReportCmd := &cobra.Command{ + Use: "report", + Short: "list all distributions in detail", + Long: `Shows detailed information about all distributions.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListDistroNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportDistros(cmd, itemNames) + }, + } distroReportCmd.Flags().String("name", "", "the distro name") + return distroReportCmd, nil } diff --git a/cmd/event.go b/cmd/event.go index b0affed..2d9741b 100644 --- a/cmd/event.go +++ b/cmd/event.go @@ -10,117 +10,118 @@ import ( "time" ) -var eventCmd = &cobra.Command{ - Use: "event", - Short: "Show and query events for their status.", - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, +func NewEventCmd() *cobra.Command { + eventCmd := &cobra.Command{ + Use: "event", + Short: "Show and query events for their status.", + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + eventCmd.AddCommand(NewEventStatusCmd()) + eventCmd.AddCommand(NewEventListCmd()) + eventCmd.AddCommand(NewEventLogCmd()) + return eventCmd } -var eventStatusCmd = &cobra.Command{ - Use: "status", - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewEventStatusCmd() *cobra.Command { + eventStatusCmd := &cobra.Command{ + Use: "status", + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - eventId, err := cmd.Flags().GetString("event-id") - if err != nil { - return err - } + eventId, err := cmd.Flags().GetString("event-id") + if err != nil { + return err + } - event, err := Client.GetTaskStatus(eventId) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), event.State) - return nil - }, + event, err := Client.GetTaskStatus(eventId) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), event.State) + return nil + }, + } + eventStatusCmd.Flags().String("event-id", "", "the event ID of the background task") + _ = eventStatusCmd.MarkFlagRequired("event-id") + return eventStatusCmd } -var eventListCmd = &cobra.Command{ - Use: "list", - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewEventListCmd() *cobra.Command { + eventListCmd := &cobra.Command{ + Use: "list", + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - user, err := cmd.Flags().GetString("user") - if err != nil { - return err - } + user, err := cmd.Flags().GetString("user") + if err != nil { + return err + } - events, err := Client.GetEvents(user) - if err != nil { - return err - } - idWidth := 0 - stateWidth := 10 - stateTimeWidth := 24 // Fixed width - nameWidth := 0 - for _, event := range events { - if len(event.ID) > idWidth { - idWidth = len(event.ID) + events, err := Client.GetEvents(user) + if err != nil { + return err } - if len(event.Name) > nameWidth { - nameWidth = len(event.Name) + idWidth := 0 + stateWidth := 10 + stateTimeWidth := 24 // Fixed width + nameWidth := 0 + for _, event := range events { + if len(event.ID) > idWidth { + idWidth = len(event.ID) + } + if len(event.Name) > nameWidth { + nameWidth = len(event.Name) + } + if len(event.State) > stateWidth { + stateWidth = len(event.State) + } } - if len(event.State) > stateWidth { - stateWidth = len(event.State) + fmt.Fprintf(cmd.OutOrStdout(), "%*s | %*s | %*s | %*s | %s \n", idWidth, "ID", nameWidth, "Name", stateWidth, "Task State", stateTimeWidth, "Time (last transitioned)", "Read by Who") + for _, event := range events { + stateTimeStruct, err := covertFloatToUtcTime(event.StateTime) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "%*s | %*s | %*s | %*s | %s \n", idWidth, event.ID, nameWidth, event.Name, stateWidth, event.State, stateTimeWidth, stateTimeStruct.Format(time.DateTime), event.ReadByWho) } - } - fmt.Fprintf(cmd.OutOrStdout(), "%*s | %*s | %*s | %*s | %s \n", idWidth, "ID", nameWidth, "Name", stateWidth, "Task State", stateTimeWidth, "Time (last transitioned)", "Read by Who") - for _, event := range events { - stateTimeStruct, err := covertFloatToUtcTime(event.StateTime) + return nil + }, + } + eventListCmd.Flags().String("user", "", "giving this parameter will show only events the user hasn't seen yet") + return eventListCmd +} + +func NewEventLogCmd() *cobra.Command { + eventLogCmd := &cobra.Command{ + Use: "log", + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - fmt.Fprintf(cmd.OutOrStdout(), "%*s | %*s | %*s | %*s | %s \n", idWidth, event.ID, nameWidth, event.Name, stateWidth, event.State, stateTimeWidth, stateTimeStruct.Format(time.DateTime), event.ReadByWho) - } - return nil - }, -} - -var eventLogCmd = &cobra.Command{ - Use: "log", - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - eventId, err := cmd.Flags().GetString("event-id") - if err != nil { - return err - } - - eventLog, err := Client.GetEventLog(eventId) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), eventLog) - return nil - }, -} - -func init() { - rootCmd.AddCommand(eventCmd) - - eventCmd.AddCommand(eventStatusCmd) - eventCmd.AddCommand(eventListCmd) - eventCmd.AddCommand(eventLogCmd) - - // local flags for status - eventStatusCmd.Flags().String("event-id", "", "the event ID of the background task") - _ = eventStatusCmd.MarkFlagRequired("event-id") - // local flags for list - eventListCmd.Flags().String("user", "", "giving this parameter will show only events the user hasn't seen yet") + eventId, err := cmd.Flags().GetString("event-id") + if err != nil { + return err + } - // local flags for log + eventLog, err := Client.GetEventLog(eventId) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), eventLog) + return nil + }, + } eventLogCmd.Flags().String("event-id", "", "the event ID of the background task") - _ = eventStatusCmd.MarkFlagRequired("event-id") + _ = eventLogCmd.MarkFlagRequired("event-id") + return eventLogCmd } diff --git a/cmd/file.go b/cmd/file.go index 1a641c0..1e2776c 100644 --- a/cmd/file.go +++ b/cmd/file.go @@ -107,211 +107,265 @@ func updateFileFromFlags(cmd *cobra.Command, file *cobbler.File) error { return err } -// fileCmd represents the file command -var fileCmd = &cobra.Command{ - Use: "file", - Short: "File management", - Long: `Let you manage files. +// NewFileCmd builds a new command that represents the file action +func NewFileCmd() *cobra.Command { + fileCmd := &cobra.Command{ + Use: "file", + Short: "File management", + Long: `Let you manage files. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-file for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + fileCmd.AddCommand(NewFileAddCmd()) + fileCmd.AddCommand(NewFileCopyCmd()) + fileCmd.AddCommand(NewFileEditCmd()) + fileCmd.AddCommand(NewFileFindCmd()) + fileCmd.AddCommand(NewFileListCmd()) + fileCmd.AddCommand(NewFileRemoveCmd()) + fileCmd.AddCommand(NewFileRenameCmd()) + fileCmd.AddCommand(NewFileReportCmd()) + return fileCmd } -var fileAddCmd = &cobra.Command{ - Use: "add", - Short: "add file", - Long: `Adds a file.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewFileAddCmd() *cobra.Command { + fileAddCmd := &cobra.Command{ + Use: "add", + Short: "add file", + Long: `Adds a file.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - newFile := cobbler.NewFile() + newFile := cobbler.NewFile() - // Get special name flag - newFile.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - // Update with the rest of the flags - err = updateFileFromFlags(cmd, &newFile) - if err != nil { - return err - } - // Now create the file via XML-RPC - file, err := Client.CreateFile(newFile) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "File %s created\n", file.Name) - return nil - }, + // Get special name flag + newFile.Name, err = cmd.Flags().GetString("name") + if err != nil { + return err + } + // Update with the rest of the flags + err = updateFileFromFlags(cmd, &newFile) + if err != nil { + return err + } + // Now create the file via XML-RPC + file, err := Client.CreateFile(newFile) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "File %s created\n", file.Name) + return nil + }, + } + addCommonArgs(fileAddCmd) + addStringFlags(fileAddCmd, fileStringFlagMetadata) + addBoolFlags(fileAddCmd, fileBoolFlagMetadata) + return fileAddCmd } -var fileCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy file", - Long: `Copies a file.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewFileCopyCmd() *cobra.Command { + fileCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy file", + Long: `Copies a file.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // Get special name and newname flags - fileName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - fileNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } + // Get special name and newname flags + fileName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + fileNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // Now copy the file - fileHandle, err := Client.GetFileHandle(fileName) - if err != nil { - return err - } - err = Client.CopyFile(fileHandle, fileNewName) - if err != nil { - return err - } - newFile, err := Client.GetFile(fileNewName, false, false) - if err != nil { - return err - } - err = updateFileFromFlags(cmd, newFile) - if err != nil { - return err - } - return Client.UpdateFile(newFile) - }, + // Now copy the file + fileHandle, err := Client.GetFileHandle(fileName) + if err != nil { + return err + } + err = Client.CopyFile(fileHandle, fileNewName) + if err != nil { + return err + } + newFile, err := Client.GetFile(fileNewName, false, false) + if err != nil { + return err + } + err = updateFileFromFlags(cmd, newFile) + if err != nil { + return err + } + return Client.UpdateFile(newFile) + }, + } + addCommonArgs(fileCopyCmd) + addStringFlags(fileCopyCmd, fileStringFlagMetadata) + addBoolFlags(fileCopyCmd, fileBoolFlagMetadata) + fileCopyCmd.Flags().String("newname", "", "the new file name") + return fileCopyCmd } -var fileEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit file", - Long: `Edits a file.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewFileEditCmd() *cobra.Command { + fileEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit file", + Long: `Edits a file.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // Get the file name - fileName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } + // Get the file name + fileName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } - // Now get the file from the API - newFile, err := Client.GetFile(fileName, false, false) - if err != nil { - return err - } - // Update the file in-memory - err = updateFileFromFlags(cmd, newFile) - if err != nil { - return err - } - // Now update the file via XML-RPC - return Client.UpdateFile(newFile) - }, + // Now get the file from the API + newFile, err := Client.GetFile(fileName, false, false) + if err != nil { + return err + } + // Update the file in-memory + err = updateFileFromFlags(cmd, newFile) + if err != nil { + return err + } + // Now update the file via XML-RPC + return Client.UpdateFile(newFile) + }, + } + addCommonArgs(fileEditCmd) + addStringFlags(fileEditCmd, fileStringFlagMetadata) + addBoolFlags(fileEditCmd, fileBoolFlagMetadata) + return fileEditCmd } -var fileFindCmd = &cobra.Command{ - Use: "find", - Short: "find file", - Long: `Finds a given file.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewFileFindCmd() *cobra.Command { + fileFindCmd := &cobra.Command{ + Use: "find", + Short: "find file", + Long: `Finds a given file.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - return FindItemNames(cmd, args, "file") - }, + return FindItemNames(cmd, args, "file") + }, + } + addCommonArgs(fileFindCmd) + addStringFlags(fileFindCmd, fileStringFlagMetadata) + addBoolFlags(fileFindCmd, fileBoolFlagMetadata) + addStringFlags(fileFindCmd, findStringFlagMetadata) + addIntFlags(fileFindCmd, findIntFlagMetadata) + addFloatFlags(fileFindCmd, findFloatFlagMetadata) + return fileFindCmd } -var fileListCmd = &cobra.Command{ - Use: "list", - Short: "list all files", - Long: `Lists all available files.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewFileListCmd() *cobra.Command { + fileListCmd := &cobra.Command{ + Use: "list", + Short: "list all files", + Long: `Lists all available files.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - fileNames, err := Client.ListFileNames() - if err != nil { - return err - } - listItems(cmd, "files", fileNames) - return nil - }, + fileNames, err := Client.ListFileNames() + if err != nil { + return err + } + listItems(cmd, "files", fileNames) + return nil + }, + } + return fileListCmd } -var fileRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove file", - Long: `Removes a given file.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewFileRemoveCmd() *cobra.Command { + fileRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove file", + Long: `Removes a given file.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - return RemoveItemRecursive(cmd, args, "file") - }, + return RemoveItemRecursive(cmd, args, "file") + }, + } + fileRemoveCmd.Flags().String("name", "", "the file name") + fileRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return fileRemoveCmd } -var fileRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename file", - Long: `Renames a given file.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewFileRenameCmd() *cobra.Command { + fileRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename file", + Long: `Renames a given file.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // Get the special name and newname flags - fileName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - fileNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } + // Get the special name and newname flags + fileName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + fileNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // Get the file handle - fileHandle, err := Client.GetFileHandle(fileName) - if err != nil { - return err - } - // Rename the file (server-side) - err = Client.RenameFile(fileHandle, fileNewName) - if err != nil { - return err - } - // Get the renamed file from the API - newFile, err := Client.GetFile(fileNewName, false, false) - if err != nil { - return err - } - // Update the file in-memory - err = updateFileFromFlags(cmd, newFile) - if err != nil { - return err - } - // Update the file via XML-RPC - return Client.UpdateFile(newFile) - }, + // Get the file handle + fileHandle, err := Client.GetFileHandle(fileName) + if err != nil { + return err + } + // Rename the file (server-side) + err = Client.RenameFile(fileHandle, fileNewName) + if err != nil { + return err + } + // Get the renamed file from the API + newFile, err := Client.GetFile(fileNewName, false, false) + if err != nil { + return err + } + // Update the file in-memory + err = updateFileFromFlags(cmd, newFile) + if err != nil { + return err + } + // Update the file via XML-RPC + return Client.UpdateFile(newFile) + }, + } + addCommonArgs(fileRenameCmd) + addStringFlags(fileRenameCmd, fileStringFlagMetadata) + addBoolFlags(fileRenameCmd, fileBoolFlagMetadata) + fileRenameCmd.Flags().String("newname", "", "the new file name") + return fileRenameCmd } func reportFiles(cmd *cobra.Command, fileNames []string) error { @@ -326,78 +380,33 @@ func reportFiles(cmd *cobra.Command, fileNames []string) error { return nil } -var fileReportCmd = &cobra.Command{ - Use: "report", - Short: "list all files in detail", - Long: `Shows detailed information about all files.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListFileNames() +func NewFileReportCmd() *cobra.Command { + fileReportCmd := &cobra.Command{ + Use: "report", + Short: "list all files in detail", + Long: `Shows detailed information about all files.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - } else { - itemNames = append(itemNames, name) - } - return reportFiles(cmd, itemNames) - }, -} - -func init() { - rootCmd.AddCommand(fileCmd) - fileCmd.AddCommand(fileAddCmd) - fileCmd.AddCommand(fileCopyCmd) - fileCmd.AddCommand(fileEditCmd) - fileCmd.AddCommand(fileFindCmd) - fileCmd.AddCommand(fileListCmd) - fileCmd.AddCommand(fileRemoveCmd) - fileCmd.AddCommand(fileRenameCmd) - fileCmd.AddCommand(fileReportCmd) - - // local flags for file add - addCommonArgs(fileAddCmd) - addStringFlags(fileAddCmd, fileStringFlagMetadata) - addBoolFlags(fileAddCmd, fileBoolFlagMetadata) - - // local flags for file copy - addCommonArgs(fileCopyCmd) - addStringFlags(fileCopyCmd, fileStringFlagMetadata) - addBoolFlags(fileCopyCmd, fileBoolFlagMetadata) - fileCopyCmd.Flags().String("newname", "", "the new file name") - - // local flags for file edit - addCommonArgs(fileEditCmd) - addStringFlags(fileEditCmd, fileStringFlagMetadata) - addBoolFlags(fileEditCmd, fileBoolFlagMetadata) - // local flags for file find - addCommonArgs(fileFindCmd) - addStringFlags(fileFindCmd, fileStringFlagMetadata) - addBoolFlags(fileFindCmd, fileBoolFlagMetadata) - addStringFlags(fileFindCmd, findStringFlagMetadata) - addIntFlags(fileFindCmd, findIntFlagMetadata) - addFloatFlags(fileFindCmd, findFloatFlagMetadata) - - // local flags for file remove - fileRemoveCmd.Flags().String("name", "", "the file name") - fileRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") - - // local flags for file rename - addCommonArgs(fileRenameCmd) - addStringFlags(fileRenameCmd, fileStringFlagMetadata) - addBoolFlags(fileRenameCmd, fileBoolFlagMetadata) - fileRenameCmd.Flags().String("newname", "", "the new file name") - - // local flags for file report + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListFileNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportFiles(cmd, itemNames) + }, + } fileReportCmd.Flags().String("name", "", "the file name") + return fileReportCmd } diff --git a/cmd/hardlink.go b/cmd/hardlink.go index b4e7e3f..f5a5a0c 100644 --- a/cmd/hardlink.go +++ b/cmd/hardlink.go @@ -9,26 +9,25 @@ import ( "github.com/spf13/cobra" ) -// hardlinkCmd represents the hardlink command -var hardlinkCmd = &cobra.Command{ - Use: "hardlink", - Short: "Hardlink files", - Long: "Hardlink all files where it is possible to improve performance.", - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +// NewHardlinkCmd builds a new commdand that represents the hardlink action +func NewHardlinkCmd() *cobra.Command { + hardlinkCmd := &cobra.Command{ + Use: "hardlink", + Short: "Hardlink files", + Long: "Hardlink all files where it is possible to improve performance.", + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - eventId, err := Client.BackgroundHardlink() - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) - return nil - }, -} - -func init() { - rootCmd.AddCommand(hardlinkCmd) + eventId, err := Client.BackgroundHardlink() + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil + }, + } + return hardlinkCmd } diff --git a/cmd/image.go b/cmd/image.go index 68121c9..7a16777 100644 --- a/cmd/image.go +++ b/cmd/image.go @@ -347,252 +347,58 @@ func updateImageFromFlags(cmd *cobra.Command, image *cobbler.Image) error { return err } -// imageCmd represents the image command -var imageCmd = &cobra.Command{ - Use: "image", - Short: "Image management", - Long: `Let you manage images. +// NewImageCmd builds a new command that represents the image action +func NewImageCmd() *cobra.Command { + imageCmd := &cobra.Command{ + Use: "image", + Short: "Image management", + Long: `Let you manage images. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-image for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, -} - -var imageAddCmd = &cobra.Command{ - Use: "add", - Short: "add image", - Long: `Adds a image.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - newImage := cobbler.NewImage() - newImage.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - // Update image in-memory - err = updateImageFromFlags(cmd, &newImage) - if err != nil { - return err - } - // Now create the image via XML-RPC - system, err := Client.CreateImage(newImage) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "System %s created\n", system.Name) - return nil - }, -} - -var imageCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy image", - Long: `Copies a image.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - imageName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - imageNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - imageHandle, err := Client.GetImageHandle(imageName) - if err != nil { - return err - } - err = Client.CopyImage(imageHandle, imageNewName) - if err != nil { - return err - } - copiedImage, err := Client.GetImage(imageNewName, false, false) - if err != nil { - return err - } - // Update image in-memory - err = updateImageFromFlags(cmd, copiedImage) - if err != nil { - return err - } - return Client.UpdateImage(copiedImage) - }, -} - -var imageEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit image", - Long: `Edits a image.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - imageName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - - imageToEdit, err := Client.GetImage(imageName, false, false) - if err != nil { - return err - } - // Update image in-memory - err = updateImageFromFlags(cmd, imageToEdit) - if err != nil { - return err - } - return Client.UpdateImage(imageToEdit) - }, -} - -var imageFindCmd = &cobra.Command{ - Use: "find", - Short: "find image", - Long: `Finds a given image.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - return FindItemNames(cmd, args, "image") - }, -} - -var imageListCmd = &cobra.Command{ - Use: "list", - Short: "list all images", - Long: `Lists all available images.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - imageNames, err := Client.ListImageNames() - if err != nil { - return err - } - listItems(cmd, "images", imageNames) - return nil - }, -} - -var imageRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove image", - Long: `Removes a given image.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return RemoveItemRecursive(cmd, args, "image") - }, -} - -var imageRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename image", - Long: `Renames a given image.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - imageName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - imageNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - imageHandle, err := Client.GetImageHandle(imageName) - if err != nil { - return err - } - err = Client.RenameImage(imageHandle, imageNewName) - if err != nil { - return err - } - renamedImage, err := Client.GetImage(imageNewName, false, false) - if err != nil { - return err - } - // Update image in-memory - err = updateImageFromFlags(cmd, renamedImage) - if err != nil { - return err - } - return Client.UpdateImage(renamedImage) - }, -} - -func reportImages(cmd *cobra.Command, imageNames []string) error { - for _, itemName := range imageNames { - system, err := Client.GetImage(itemName, false, false) - if err != nil { - return err - } - printStructured(cmd, system) - fmt.Fprintln(cmd.OutOrStdout(), "") + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, } - return nil + imageCmd.AddCommand(NewImageAddCmd()) + imageCmd.AddCommand(NewImageCopyCmd()) + imageCmd.AddCommand(NewImageEditCmd()) + imageCmd.AddCommand(NewImageFindCmd()) + imageCmd.AddCommand(NewImageListCmd()) + imageCmd.AddCommand(NewImageRemoveCmd()) + imageCmd.AddCommand(NewImageRenameCmd()) + imageCmd.AddCommand(NewImageReportCmd()) + return imageCmd } -var imageReportCmd = &cobra.Command{ - Use: "report", - Short: "list all images in detail", - Long: `Shows detailed information about all images.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListImageNames() +func NewImageAddCmd() *cobra.Command { + imageAddCmd := &cobra.Command{ + Use: "add", + Short: "add image", + Long: `Adds a image.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - } else { - itemNames = append(itemNames, name) - } - return reportImages(cmd, itemNames) - }, -} - -func init() { - rootCmd.AddCommand(imageCmd) - imageCmd.AddCommand(imageAddCmd) - imageCmd.AddCommand(imageCopyCmd) - imageCmd.AddCommand(imageEditCmd) - imageCmd.AddCommand(imageFindCmd) - imageCmd.AddCommand(imageListCmd) - imageCmd.AddCommand(imageRemoveCmd) - imageCmd.AddCommand(imageRenameCmd) - imageCmd.AddCommand(imageReportCmd) - // local flags for image add + newImage := cobbler.NewImage() + newImage.Name, err = cmd.Flags().GetString("name") + if err != nil { + return err + } + // Update image in-memory + err = updateImageFromFlags(cmd, &newImage) + if err != nil { + return err + } + // Now create the image via XML-RPC + system, err := Client.CreateImage(newImage) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "System %s created\n", system.Name) + return nil + }, + } addCommonArgs(imageAddCmd) addStringFlags(imageAddCmd, imageStringFlagMetadata) addIntFlags(imageAddCmd, imageIntFlagMetadata) @@ -600,8 +406,49 @@ func init() { addBoolFlags(imageAddCmd, imageBoolFlagMetadata) addStringSliceFlags(imageAddCmd, imageStringSliceFlagMetadata) imageAddCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return imageAddCmd +} + +func NewImageCopyCmd() *cobra.Command { + imageCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy image", + Long: `Copies a image.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for image copy + imageName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + imageNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } + + imageHandle, err := Client.GetImageHandle(imageName) + if err != nil { + return err + } + err = Client.CopyImage(imageHandle, imageNewName) + if err != nil { + return err + } + copiedImage, err := Client.GetImage(imageNewName, false, false) + if err != nil { + return err + } + // Update image in-memory + err = updateImageFromFlags(cmd, copiedImage) + if err != nil { + return err + } + return Client.UpdateImage(copiedImage) + }, + } addCommonArgs(imageCopyCmd) addStringFlags(imageCopyCmd, imageStringFlagMetadata) addIntFlags(imageCopyCmd, imageIntFlagMetadata) @@ -610,8 +457,37 @@ func init() { addStringSliceFlags(imageCopyCmd, imageStringSliceFlagMetadata) imageCopyCmd.Flags().String("newname", "", "the new image name") imageCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return imageCopyCmd +} - // local flags for image edit +func NewImageEditCmd() *cobra.Command { + imageEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit image", + Long: `Edits a image.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + imageName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + + imageToEdit, err := Client.GetImage(imageName, false, false) + if err != nil { + return err + } + // Update image in-memory + err = updateImageFromFlags(cmd, imageToEdit) + if err != nil { + return err + } + return Client.UpdateImage(imageToEdit) + }, + } addCommonArgs(imageEditCmd) addStringFlags(imageEditCmd, imageStringFlagMetadata) addIntFlags(imageEditCmd, imageIntFlagMetadata) @@ -619,8 +495,22 @@ func init() { addBoolFlags(imageEditCmd, imageBoolFlagMetadata) addStringSliceFlags(imageEditCmd, imageStringSliceFlagMetadata) imageEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return imageEditCmd +} - // local flags for image find +func NewImageFindCmd() *cobra.Command { + imageFindCmd := &cobra.Command{ + Use: "find", + Short: "find image", + Long: `Finds a given image.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + return FindItemNames(cmd, args, "image") + }, + } addCommonArgs(imageFindCmd) addStringFlags(imageFindCmd, imageStringFlagMetadata) addIntFlags(imageFindCmd, imageIntFlagMetadata) @@ -630,12 +520,90 @@ func init() { addStringFlags(imageFindCmd, findStringFlagMetadata) addIntFlags(imageFindCmd, findIntFlagMetadata) addFloatFlags(imageFindCmd, findFloatFlagMetadata) + return imageFindCmd +} + +func NewImageListCmd() *cobra.Command { + imageListCmd := &cobra.Command{ + Use: "list", + Short: "list all images", + Long: `Lists all available images.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for image remove + imageNames, err := Client.ListImageNames() + if err != nil { + return err + } + listItems(cmd, "images", imageNames) + return nil + }, + } + return imageListCmd +} + +func NewImageRemoveCmd() *cobra.Command { + imageRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove image", + Long: `Removes a given image.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + return RemoveItemRecursive(cmd, args, "image") + }, + } imageRemoveCmd.Flags().String("name", "", "the image name") imageRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return imageRemoveCmd +} + +func NewImageRenameCmd() *cobra.Command { + imageRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename image", + Long: `Renames a given image.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for image rename + imageName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + imageNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } + + imageHandle, err := Client.GetImageHandle(imageName) + if err != nil { + return err + } + err = Client.RenameImage(imageHandle, imageNewName) + if err != nil { + return err + } + renamedImage, err := Client.GetImage(imageNewName, false, false) + if err != nil { + return err + } + // Update image in-memory + err = updateImageFromFlags(cmd, renamedImage) + if err != nil { + return err + } + return Client.UpdateImage(renamedImage) + }, + } addCommonArgs(imageRenameCmd) addStringFlags(imageRenameCmd, imageStringFlagMetadata) addIntFlags(imageRenameCmd, imageIntFlagMetadata) @@ -644,7 +612,48 @@ func init() { addStringSliceFlags(imageRenameCmd, imageStringSliceFlagMetadata) imageRenameCmd.Flags().String("newname", "", "the new image name") imageRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return imageRenameCmd +} + +func reportImages(cmd *cobra.Command, imageNames []string) error { + for _, itemName := range imageNames { + system, err := Client.GetImage(itemName, false, false) + if err != nil { + return err + } + printStructured(cmd, system) + fmt.Fprintln(cmd.OutOrStdout(), "") + } + return nil +} + +func NewImageReportCmd() *cobra.Command { + imageReportCmd := &cobra.Command{ + Use: "report", + Short: "list all images in detail", + Long: `Shows detailed information about all images.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for image report + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListImageNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportImages(cmd, itemNames) + }, + } imageReportCmd.Flags().String("name", "", "the image name") + return imageReportCmd } diff --git a/cmd/import.go b/cmd/import.go index 46e7e5d..e98c567 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -10,74 +10,70 @@ import ( "github.com/spf13/cobra" ) -// importCmd represents the import command -var importCmd = &cobra.Command{ - Use: "import", - Short: "Import operating system distributions", - Long: `Import operating system distributions into Cobbler. This could be a mounted ISO, network rsync mirror or a tree in the filesystem. +// NewImportCmd builds a new command that represents the import action +func NewImportCmd() *cobra.Command { + importCmd := &cobra.Command{ + Use: "import", + Short: "Import operating system distributions", + Long: `Import operating system distributions into Cobbler. This could be a mounted ISO, network rsync mirror or a tree in the filesystem. See https://cobbler.readthedocs.io/en/latest/quickstart-guide.html#importing-your-first-distribution for more information.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - archOption, err := cmd.Flags().GetString("arch") - if err != nil { - return err - } - autoinstallOption, err := cmd.Flags().GetString("autoinstall") - if err != nil { - return err - } - availableAsOption, err := cmd.Flags().GetString("available-as") - if err != nil { - return err - } - breedOption, err := cmd.Flags().GetString("breed") - if err != nil { - return err - } - nameOption, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - osVersionOption, err := cmd.Flags().GetString("os-version") - if err != nil { - return err - } - pathOption, err := cmd.Flags().GetString("path") - if err != nil { - return err - } - rsyncFlagsOption, err := cmd.Flags().GetString("rsync-flags") - if err != nil { - return err - } - var backgroundOptions = cobblerclient.BackgroundImportOptions{ - Path: pathOption, - Name: nameOption, - AvailableAs: availableAsOption, - AutoinstallFile: autoinstallOption, - RsyncFlags: rsyncFlagsOption, - Arch: archOption, - Breed: breedOption, - OsVersion: osVersionOption, - } - eventId, err := Client.BackgroundImport(backgroundOptions) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) - return nil - }, -} - -func init() { - rootCmd.AddCommand(importCmd) - - //local flags + archOption, err := cmd.Flags().GetString("arch") + if err != nil { + return err + } + autoinstallOption, err := cmd.Flags().GetString("autoinstall") + if err != nil { + return err + } + availableAsOption, err := cmd.Flags().GetString("available-as") + if err != nil { + return err + } + breedOption, err := cmd.Flags().GetString("breed") + if err != nil { + return err + } + nameOption, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + osVersionOption, err := cmd.Flags().GetString("os-version") + if err != nil { + return err + } + pathOption, err := cmd.Flags().GetString("path") + if err != nil { + return err + } + rsyncFlagsOption, err := cmd.Flags().GetString("rsync-flags") + if err != nil { + return err + } + var backgroundOptions = cobblerclient.BackgroundImportOptions{ + Path: pathOption, + Name: nameOption, + AvailableAs: availableAsOption, + AutoinstallFile: autoinstallOption, + RsyncFlags: rsyncFlagsOption, + Arch: archOption, + Breed: breedOption, + OsVersion: osVersionOption, + } + eventId, err := Client.BackgroundImport(backgroundOptions) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil + }, + } importCmd.Flags().String("arch", "", "the architechture of the OS") importCmd.Flags().String("autoinstall", "", "assign this autoinstall file") importCmd.Flags().String("available-as", "", "do not mirror, the tree is here") @@ -86,4 +82,5 @@ func init() { importCmd.Flags().String("os-version", "", "the version of the OS") importCmd.Flags().String("path", "", "local path or rsync location") importCmd.Flags().String("rsync-flags", "", "pass additional flags to rsync") + return importCmd } diff --git a/cmd/list.go b/cmd/list.go index cbeb19f..0a64930 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -10,67 +10,70 @@ import ( "sort" ) -// listCmd represents the list command -var listCmd = &cobra.Command{ - Use: "list", - Short: "List configuration", - Long: `Lists all configuration which Cobbler can obtain from the saved data. There are also report subcommands for +// NewListCmd represents the list command +func NewListCmd() *cobra.Command { + listCmd := &cobra.Command{ + Use: "list", + Short: "List configuration", + Long: `Lists all configuration which Cobbler can obtain from the saved data. There are also report subcommands for most of the other Cobbler commands (currently: distro, profile, system, repo, image, mgmtclass, package, file, menu). Identical to 'cobbler report'`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - distroNames, err := Client.ListDistroNames() - if err != nil { - return err - } - profileNames, err := Client.ListProfileNames() - if err != nil { - return err - } - systemNames, err := Client.ListSystemNames() - if err != nil { - return err - } - repoNames, err := Client.ListRepoNames() - if err != nil { - return err - } - imageNames, err := Client.ListImageNames() - if err != nil { - return err - } - mgmtClassNames, err := Client.ListMgmtClassNames() - if err != nil { - return err - } - packageNames, err := Client.ListPackageNames() - if err != nil { - return err - } - fileNames, err := Client.ListFileNames() - if err != nil { - return err - } - menuNames, err := Client.ListMenuNames() - if err != nil { - return err - } - listItems(cmd, "distros", distroNames) - listItems(cmd, "profiles", profileNames) - listItems(cmd, "systems", systemNames) - listItems(cmd, "repos", repoNames) - listItems(cmd, "images", imageNames) - listItems(cmd, "mgmtclasses", mgmtClassNames) - listItems(cmd, "packages", packageNames) - listItems(cmd, "files", fileNames) - listItems(cmd, "menus", menuNames) - return nil - }, + distroNames, err := Client.ListDistroNames() + if err != nil { + return err + } + profileNames, err := Client.ListProfileNames() + if err != nil { + return err + } + systemNames, err := Client.ListSystemNames() + if err != nil { + return err + } + repoNames, err := Client.ListRepoNames() + if err != nil { + return err + } + imageNames, err := Client.ListImageNames() + if err != nil { + return err + } + mgmtClassNames, err := Client.ListMgmtClassNames() + if err != nil { + return err + } + packageNames, err := Client.ListPackageNames() + if err != nil { + return err + } + fileNames, err := Client.ListFileNames() + if err != nil { + return err + } + menuNames, err := Client.ListMenuNames() + if err != nil { + return err + } + listItems(cmd, "distros", distroNames) + listItems(cmd, "profiles", profileNames) + listItems(cmd, "systems", systemNames) + listItems(cmd, "repos", repoNames) + listItems(cmd, "images", imageNames) + listItems(cmd, "mgmtclasses", mgmtClassNames) + listItems(cmd, "packages", packageNames) + listItems(cmd, "files", fileNames) + listItems(cmd, "menus", menuNames) + return nil + }, + } + return listCmd } func listItems(cmd *cobra.Command, what string, items []string) { @@ -81,7 +84,3 @@ func listItems(cmd *cobra.Command, what string, items []string) { } fmt.Fprintln(cmd.OutOrStdout(), "") } - -func init() { - rootCmd.AddCommand(listCmd) -} diff --git a/cmd/menu.go b/cmd/menu.go index 8cca9ed..14cb7e4 100644 --- a/cmd/menu.go +++ b/cmd/menu.go @@ -51,199 +51,249 @@ func updateMenuFromFlags(cmd *cobra.Command, menu *cobbler.Menu) error { return err } -// menuCmd represents the menu command -var menuCmd = &cobra.Command{ - Use: "menu", - Short: "Menu management", - Long: `Let you manage menus. +// NewMenuCmd builds a new command that represents the menu action +func NewMenuCmd() *cobra.Command { + menuCmd := &cobra.Command{ + Use: "menu", + Short: "Menu management", + Long: `Let you manage menus. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-menu for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + menuCmd.AddCommand(NewMenuAddCmd()) + menuCmd.AddCommand(NewMenuCopyCmd()) + menuCmd.AddCommand(NewMenuEditCmd()) + menuCmd.AddCommand(NewMenuFindCmd()) + menuCmd.AddCommand(NewMenuListCmd()) + menuCmd.AddCommand(NewMenuRemoveCmd()) + menuCmd.AddCommand(NewMenuRenameCmd()) + menuCmd.AddCommand(NewMenuReportCmd()) + return menuCmd } -var menuAddCmd = &cobra.Command{ - Use: "add", - Short: "add menu", - Long: `Adds a menu.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewMenuAddCmd() *cobra.Command { + menuAddCmd := &cobra.Command{ + Use: "add", + Short: "add menu", + Long: `Adds a menu.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - newMenu := cobbler.NewMenu() + newMenu := cobbler.NewMenu() - // internal fields (ctime, mtime, depth, uid, source-repos, tree-build-time) cannot be modified - newMenu.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - // Update menu in-memory - err = updateMenuFromFlags(cmd, &newMenu) - if err != nil { - return err - } - // Now create the menu via XML-RPC - menu, err := Client.CreateMenu(newMenu) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Menu %s created\n", menu.Name) - return nil - }, + // internal fields (ctime, mtime, depth, uid, source-repos, tree-build-time) cannot be modified + newMenu.Name, err = cmd.Flags().GetString("name") + if err != nil { + return err + } + // Update menu in-memory + err = updateMenuFromFlags(cmd, &newMenu) + if err != nil { + return err + } + // Now create the menu via XML-RPC + menu, err := Client.CreateMenu(newMenu) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Menu %s created\n", menu.Name) + return nil + }, + } + addCommonArgs(menuAddCmd) + addStringFlags(menuAddCmd, menuStringFlagMetadata) + return menuAddCmd } -var menuCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy menu", - Long: `Copies a menu.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewMenuCopyCmd() *cobra.Command { + menuCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy menu", + Long: `Copies a menu.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - menuName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - menuNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } + menuName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + menuNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - menuHandle, err := Client.GetMenuHandle(menuName) - if err != nil { - return err - } - err = Client.CopyMenu(menuHandle, menuNewName) - if err != nil { - return err - } - newMenu, err := Client.GetMenu(menuNewName, false, false) - if err != nil { - return err - } - err = updateMenuFromFlags(cmd, newMenu) - if err != nil { - return err - } - return Client.UpdateMenu(newMenu) - }, + menuHandle, err := Client.GetMenuHandle(menuName) + if err != nil { + return err + } + err = Client.CopyMenu(menuHandle, menuNewName) + if err != nil { + return err + } + newMenu, err := Client.GetMenu(menuNewName, false, false) + if err != nil { + return err + } + err = updateMenuFromFlags(cmd, newMenu) + if err != nil { + return err + } + return Client.UpdateMenu(newMenu) + }, + } + addCommonArgs(menuCopyCmd) + addStringFlags(menuCopyCmd, menuStringFlagMetadata) + menuCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return menuCopyCmd } -var menuEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit menu", - Long: `Edits a menu.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewMenuEditCmd() *cobra.Command { + menuEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit menu", + Long: `Edits a menu.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - menuName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } + menuName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } - menuToEdit, err := Client.GetMenu(menuName, false, false) - if err != nil { - return err - } - err = updateMenuFromFlags(cmd, menuToEdit) - if err != nil { - return err - } - return Client.UpdateMenu(menuToEdit) - }, + menuToEdit, err := Client.GetMenu(menuName, false, false) + if err != nil { + return err + } + err = updateMenuFromFlags(cmd, menuToEdit) + if err != nil { + return err + } + return Client.UpdateMenu(menuToEdit) + }, + } + addCommonArgs(menuEditCmd) + addStringFlags(menuEditCmd, menuStringFlagMetadata) + menuEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return menuEditCmd } -var menuFindCmd = &cobra.Command{ - Use: "find", - Short: "find menu", - Long: `Finds a given menu.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewMenuFindCmd() *cobra.Command { + menuFindCmd := &cobra.Command{ + Use: "find", + Short: "find menu", + Long: `Finds a given menu.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - return FindItemNames(cmd, args, "menu") - }, + return FindItemNames(cmd, args, "menu") + }, + } + addCommonArgs(menuFindCmd) + addStringFlags(menuFindCmd, menuStringFlagMetadata) + addStringFlags(menuFindCmd, findStringFlagMetadata) + addIntFlags(menuFindCmd, findIntFlagMetadata) + addFloatFlags(menuFindCmd, findFloatFlagMetadata) + return menuFindCmd } -var menuListCmd = &cobra.Command{ - Use: "list", - Short: "list all menus", - Long: `Lists all available menus.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewMenuListCmd() *cobra.Command { + menuListCmd := &cobra.Command{ + Use: "list", + Short: "list all menus", + Long: `Lists all available menus.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - menuNames, err := Client.ListMenuNames() - if err != nil { - return err - } - listItems(cmd, "menus", menuNames) - return nil - }, + menuNames, err := Client.ListMenuNames() + if err != nil { + return err + } + listItems(cmd, "menus", menuNames) + return nil + }, + } + return menuListCmd } -var menuRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove menu", - Long: `Removes a given menu.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewMenuRemoveCmd() *cobra.Command { + menuRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove menu", + Long: `Removes a given menu.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - return RemoveItemRecursive(cmd, args, "menu") - }, + return RemoveItemRecursive(cmd, args, "menu") + }, + } + menuRemoveCmd.Flags().String("name", "", "the menu name") + menuRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return menuRemoveCmd } -var menuRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename menu", - Long: `Renames a given menu.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewMenuRenameCmd() *cobra.Command { + menuRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename menu", + Long: `Renames a given menu.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - menuName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - menuNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } + menuName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + menuNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - menuHandle, err := Client.GetMenuHandle(menuName) - if err != nil { - return err - } - err = Client.RenameMenu(menuHandle, menuNewName) - if err != nil { - return err - } - newMenu, err := Client.GetMenu(menuNewName, false, false) - if err != nil { - return err - } - err = updateMenuFromFlags(cmd, newMenu) - if err != nil { - return err - } - return Client.UpdateMenu(newMenu) - }, + menuHandle, err := Client.GetMenuHandle(menuName) + if err != nil { + return err + } + err = Client.RenameMenu(menuHandle, menuNewName) + if err != nil { + return err + } + newMenu, err := Client.GetMenu(menuNewName, false, false) + if err != nil { + return err + } + err = updateMenuFromFlags(cmd, newMenu) + if err != nil { + return err + } + return Client.UpdateMenu(newMenu) + }, + } + addCommonArgs(menuRenameCmd) + addStringFlags(menuRenameCmd, menuStringFlagMetadata) + menuRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return menuRenameCmd } func reportMenus(cmd *cobra.Command, menuNames []string) error { @@ -258,74 +308,33 @@ func reportMenus(cmd *cobra.Command, menuNames []string) error { return nil } -var menuReportCmd = &cobra.Command{ - Use: "report", - Short: "list all menus in detail", - Long: `Shows detailed information about all menus.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListMenuNames() +func NewMenuReportCmd() *cobra.Command { + menuReportCmd := &cobra.Command{ + Use: "report", + Short: "list all menus in detail", + Long: `Shows detailed information about all menus.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - } else { - itemNames = append(itemNames, name) - } - return reportMenus(cmd, itemNames) - }, -} -func init() { - rootCmd.AddCommand(menuCmd) - menuCmd.AddCommand(menuAddCmd) - menuCmd.AddCommand(menuCopyCmd) - menuCmd.AddCommand(menuEditCmd) - menuCmd.AddCommand(menuFindCmd) - menuCmd.AddCommand(menuListCmd) - menuCmd.AddCommand(menuRemoveCmd) - menuCmd.AddCommand(menuRenameCmd) - menuCmd.AddCommand(menuReportCmd) - - // local flags for menu add - addCommonArgs(menuAddCmd) - addStringFlags(menuAddCmd, menuStringFlagMetadata) - - // local flags for menu copy - addCommonArgs(menuCopyCmd) - addStringFlags(menuCopyCmd, menuStringFlagMetadata) - menuCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") - - // local flags for menu edit - addCommonArgs(menuEditCmd) - addStringFlags(menuEditCmd, menuStringFlagMetadata) - menuEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") - - // local flags for menu find - addCommonArgs(menuFindCmd) - addStringFlags(menuFindCmd, menuStringFlagMetadata) - addStringFlags(menuFindCmd, findStringFlagMetadata) - addIntFlags(menuFindCmd, findIntFlagMetadata) - addFloatFlags(menuFindCmd, findFloatFlagMetadata) - - // local flags for menu remove - menuRemoveCmd.Flags().String("name", "", "the menu name") - menuRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") - - // local flags for menu rename - addCommonArgs(menuRenameCmd) - addStringFlags(menuRenameCmd, menuStringFlagMetadata) - menuRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") - - // local flags for menu report + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListMenuNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportMenus(cmd, itemNames) + }, + } menuReportCmd.Flags().String("name", "", "the menu name") + return menuReportCmd } diff --git a/cmd/mgmtclass.go b/cmd/mgmtclass.go index d047d7d..69b72db 100644 --- a/cmd/mgmtclass.go +++ b/cmd/mgmtclass.go @@ -102,275 +102,113 @@ func updateMgmtClassFromFlags(cmd *cobra.Command, mgmtClass *cobbler.MgmtClass) return err } -// mgmtclassCmd represents the mgmtclass command -var mgmtclassCmd = &cobra.Command{ - Use: "mgmtclass", - Short: "Mgmtclass management", - Long: `Let you manage mgmtclasses. +// NewMgmtClassCmd builds a new command that represents the mgmtclass action +func NewMgmtClassCmd() *cobra.Command { + mgmtclassCmd := &cobra.Command{ + Use: "mgmtclass", + Short: "Mgmtclass management", + Long: `Let you manage mgmtclasses. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-mgmtclass for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, -} - -var mgmtclassAddCmd = &cobra.Command{ - Use: "add", - Short: "add mgmtclass", - Long: `Adds a mgmtclass.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - newMgmtClass := cobbler.NewMgmtClass() - - // Get special name flag - newMgmtClass.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - // Update with the rest of the flags - err = updateMgmtClassFromFlags(cmd, &newMgmtClass) - if err != nil { - return err - } - // Now create the file via XML-RPC - mgmtClass, err := Client.CreateMgmtClass(newMgmtClass) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Mgmtclass %s created\n", mgmtClass.Name) - return nil - }, -} - -var mgmtclassCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy mgmtclass", - Long: `Copies a mgmtclass.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get special name and newname flags - mgmtClassName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - mgmtClassNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - // Get API handle - mgmtClassHandle, err := Client.GetMgmtClassHandle(mgmtClassName) - if err != nil { - return err - } - // Copy the mgmtclass server-side - err = Client.CopyMgmtClass(mgmtClassHandle, mgmtClassNewName) - if err != nil { - return err - } - // Get the copied mgmtclass - newMgmtClass, err := Client.GetMgmtClass(mgmtClassNewName, false, false) - if err != nil { - return err - } - // Update the mgmtclass in-memory - err = updateMgmtClassFromFlags(cmd, newMgmtClass) - if err != nil { - return err - } - // Update the mgmtclass via XML-RPC - return Client.UpdateMgmtClass(newMgmtClass) - }, -} - -var mgmtclassEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit mgmtclass", - Long: `Edits a mgmtclass.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Collect CLI flags - mgmtClassName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - - // Get mgmtclass from the API - mgmtClassToEdit, err := Client.GetMgmtClass(mgmtClassName, false, false) - if err != nil { - return err - } - // Update mgmtclass in-memory - err = updateMgmtClassFromFlags(cmd, mgmtClassToEdit) - if err != nil { - return err - } - // Update the mgmtclass via XML-RPC - return Client.UpdateMgmtClass(mgmtClassToEdit) - }, -} - -var mgmtclassFindCmd = &cobra.Command{ - Use: "find", - Short: "find mgmtclass", - Long: `Finds a given mgmtclass.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return FindItemNames(cmd, args, "mgmtclass") - }, -} - -var mgmtclassListCmd = &cobra.Command{ - Use: "list", - Short: "list all mgmtclasses", - Long: `Lists all available mgmtclasses.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - mgmtclassNames, err := Client.ListMgmtClassNames() - if err != nil { - return err - } - listItems(cmd, "mgmtclasses", mgmtclassNames) - return nil - }, -} - -var mgmtclassRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove mgmtclass", - Long: `Removes a given mgmtclass.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return RemoveItemRecursive(cmd, args, "mgmtclass") - }, -} - -var mgmtclassRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename mgmtclass", - Long: `Renames a given mgmtclass.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get the special name and newname flags - mgmtClassName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - mgmtClassNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - // Get the mgmtclass handle - mgmtClassHandle, err := Client.GetMgmtClassHandle(mgmtClassName) - if err != nil { - return err - } - // Rename the mgmtclass server-side - err = Client.RenameMgmtClass(mgmtClassHandle, mgmtClassNewName) - if err != nil { - return err - } - // Get the renamed mgmtclass - renamedMgmtClass, err := Client.GetMgmtClass(mgmtClassNewName, false, false) - if err != nil { - return err - } - // Update mgmtclass in-memory - err = updateMgmtClassFromFlags(cmd, renamedMgmtClass) - if err != nil { - return err - } - // Update the mgmtclass via XML-RPC - return Client.UpdateMgmtClass(renamedMgmtClass) - }, -} - -func reportMgmtClasses(cmd *cobra.Command, mgmtClassNames []string) error { - for _, itemName := range mgmtClassNames { - system, err := Client.GetMgmtClass(itemName, false, false) - if err != nil { - return err - } - printStructured(cmd, system) - fmt.Fprintln(cmd.OutOrStdout(), "") + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, } - return nil + mgmtclassCmd.AddCommand(NewMgmtClassAddCmd()) + mgmtclassCmd.AddCommand(NewMgmtClassCopyCmd()) + mgmtclassCmd.AddCommand(NewMgmtClassEditCmd()) + mgmtclassCmd.AddCommand(NewMgmtClassFindCmd()) + mgmtclassCmd.AddCommand(NewMgmtClassListCmd()) + mgmtclassCmd.AddCommand(NewMgmtClassRemoveCmd()) + mgmtclassCmd.AddCommand(NewMgmtClassRenameCmd()) + mgmtclassCmd.AddCommand(NewMgmtClassReportCmd()) + return mgmtclassCmd } -var mgmtclassReportCmd = &cobra.Command{ - Use: "report", - Short: "list all mgmtclasses in detail", - Long: `Shows detailed information about all mgmtclasses.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListMgmtClassNames() +func NewMgmtClassAddCmd() *cobra.Command { + mgmtclassAddCmd := &cobra.Command{ + Use: "add", + Short: "add mgmtclass", + Long: `Adds a mgmtclass.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - } else { - itemNames = append(itemNames, name) - } - return reportMgmtClasses(cmd, itemNames) - }, -} -func init() { - rootCmd.AddCommand(mgmtclassCmd) - mgmtclassCmd.AddCommand(mgmtclassAddCmd) - mgmtclassCmd.AddCommand(mgmtclassCopyCmd) - mgmtclassCmd.AddCommand(mgmtclassEditCmd) - mgmtclassCmd.AddCommand(mgmtclassFindCmd) - mgmtclassCmd.AddCommand(mgmtclassListCmd) - mgmtclassCmd.AddCommand(mgmtclassRemoveCmd) - mgmtclassCmd.AddCommand(mgmtclassRenameCmd) - mgmtclassCmd.AddCommand(mgmtclassReportCmd) + newMgmtClass := cobbler.NewMgmtClass() - // local flags for mgmtclass add + // Get special name flag + newMgmtClass.Name, err = cmd.Flags().GetString("name") + if err != nil { + return err + } + // Update with the rest of the flags + err = updateMgmtClassFromFlags(cmd, &newMgmtClass) + if err != nil { + return err + } + // Now create the file via XML-RPC + mgmtClass, err := Client.CreateMgmtClass(newMgmtClass) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Mgmtclass %s created\n", mgmtClass.Name) + return nil + }, + } addCommonArgs(mgmtclassAddCmd) addStringFlags(mgmtclassAddCmd, mgmtclassStringFlagMetadata) addBoolFlags(mgmtclassAddCmd, mgmtclassBoolFlagMetadata) addStringSliceFlags(mgmtclassAddCmd, mgmtclassStringSliceFlagMetadata) addMapFlags(mgmtclassAddCmd, mgmtclassStringMapFlagMetadata) + return mgmtclassAddCmd +} + +func NewMgmtClassCopyCmd() *cobra.Command { + mgmtclassCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy mgmtclass", + Long: `Copies a mgmtclass.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for mgmtclass copy + // Get special name and newname flags + mgmtClassName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + mgmtClassNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } + + // Get API handle + mgmtClassHandle, err := Client.GetMgmtClassHandle(mgmtClassName) + if err != nil { + return err + } + // Copy the mgmtclass server-side + err = Client.CopyMgmtClass(mgmtClassHandle, mgmtClassNewName) + if err != nil { + return err + } + // Get the copied mgmtclass + newMgmtClass, err := Client.GetMgmtClass(mgmtClassNewName, false, false) + if err != nil { + return err + } + // Update the mgmtclass in-memory + err = updateMgmtClassFromFlags(cmd, newMgmtClass) + if err != nil { + return err + } + // Update the mgmtclass via XML-RPC + return Client.UpdateMgmtClass(newMgmtClass) + }, + } addCommonArgs(mgmtclassCopyCmd) addStringFlags(mgmtclassCopyCmd, mgmtclassStringFlagMetadata) addBoolFlags(mgmtclassCopyCmd, mgmtclassBoolFlagMetadata) @@ -378,16 +216,63 @@ func init() { addMapFlags(mgmtclassCopyCmd, mgmtclassStringMapFlagMetadata) mgmtclassCopyCmd.Flags().String("newname", "", "the new mgmtclass name") mgmtclassCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return mgmtclassCopyCmd +} + +func NewMgmtClassEditCmd() *cobra.Command { + mgmtclassEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit mgmtclass", + Long: `Edits a mgmtclass.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // Collect CLI flags + mgmtClassName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } - // local flags for mgmtclass edit + // Get mgmtclass from the API + mgmtClassToEdit, err := Client.GetMgmtClass(mgmtClassName, false, false) + if err != nil { + return err + } + // Update mgmtclass in-memory + err = updateMgmtClassFromFlags(cmd, mgmtClassToEdit) + if err != nil { + return err + } + // Update the mgmtclass via XML-RPC + return Client.UpdateMgmtClass(mgmtClassToEdit) + }, + } addCommonArgs(mgmtclassEditCmd) addStringFlags(mgmtclassEditCmd, mgmtclassStringFlagMetadata) addBoolFlags(mgmtclassEditCmd, mgmtclassBoolFlagMetadata) addStringSliceFlags(mgmtclassEditCmd, mgmtclassStringSliceFlagMetadata) addMapFlags(mgmtclassEditCmd, mgmtclassStringMapFlagMetadata) mgmtclassEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return mgmtclassEditCmd +} - // local flags for mgmtclass find +func NewMgmtClassFindCmd() *cobra.Command { + mgmtclassFindCmd := &cobra.Command{ + Use: "find", + Short: "find mgmtclass", + Long: `Finds a given mgmtclass.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + return FindItemNames(cmd, args, "mgmtclass") + }, + } addCommonArgs(mgmtclassFindCmd) addStringFlags(mgmtclassFindCmd, mgmtclassStringFlagMetadata) addBoolFlags(mgmtclassFindCmd, mgmtclassBoolFlagMetadata) @@ -396,12 +281,95 @@ func init() { addStringFlags(mgmtclassFindCmd, findStringFlagMetadata) addIntFlags(mgmtclassFindCmd, findIntFlagMetadata) addFloatFlags(mgmtclassFindCmd, findFloatFlagMetadata) + return mgmtclassFindCmd +} + +func NewMgmtClassListCmd() *cobra.Command { + mgmtclassListCmd := &cobra.Command{ + Use: "list", + Short: "list all mgmtclasses", + Long: `Lists all available mgmtclasses.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for mgmtclass remove + mgmtclassNames, err := Client.ListMgmtClassNames() + if err != nil { + return err + } + listItems(cmd, "mgmtclasses", mgmtclassNames) + return nil + }, + } + return mgmtclassListCmd +} + +func NewMgmtClassRemoveCmd() *cobra.Command { + mgmtclassRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove mgmtclass", + Long: `Removes a given mgmtclass.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + return RemoveItemRecursive(cmd, args, "mgmtclass") + }, + } mgmtclassRemoveCmd.Flags().String("name", "", "the mgmtclass name") mgmtclassRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return mgmtclassRemoveCmd +} + +func NewMgmtClassRenameCmd() *cobra.Command { + mgmtclassRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename mgmtclass", + Long: `Renames a given mgmtclass.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for mgmtclass rename + // Get the special name and newname flags + mgmtClassName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + mgmtClassNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } + + // Get the mgmtclass handle + mgmtClassHandle, err := Client.GetMgmtClassHandle(mgmtClassName) + if err != nil { + return err + } + // Rename the mgmtclass server-side + err = Client.RenameMgmtClass(mgmtClassHandle, mgmtClassNewName) + if err != nil { + return err + } + // Get the renamed mgmtclass + renamedMgmtClass, err := Client.GetMgmtClass(mgmtClassNewName, false, false) + if err != nil { + return err + } + // Update mgmtclass in-memory + err = updateMgmtClassFromFlags(cmd, renamedMgmtClass) + if err != nil { + return err + } + // Update the mgmtclass via XML-RPC + return Client.UpdateMgmtClass(renamedMgmtClass) + }, + } addCommonArgs(mgmtclassRenameCmd) addStringFlags(mgmtclassRenameCmd, mgmtclassStringFlagMetadata) addBoolFlags(mgmtclassRenameCmd, mgmtclassBoolFlagMetadata) @@ -409,7 +377,48 @@ func init() { addMapFlags(mgmtclassRenameCmd, mgmtclassStringMapFlagMetadata) mgmtclassRenameCmd.Flags().String("newname", "", "the new mgmtclass name") mgmtclassRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return mgmtclassRenameCmd +} + +func reportMgmtClasses(cmd *cobra.Command, mgmtClassNames []string) error { + for _, itemName := range mgmtClassNames { + system, err := Client.GetMgmtClass(itemName, false, false) + if err != nil { + return err + } + printStructured(cmd, system) + fmt.Fprintln(cmd.OutOrStdout(), "") + } + return nil +} + +func NewMgmtClassReportCmd() *cobra.Command { + mgmtclassReportCmd := &cobra.Command{ + Use: "report", + Short: "list all mgmtclasses in detail", + Long: `Shows detailed information about all mgmtclasses.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for mgmtclass report + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListMgmtClassNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportMgmtClasses(cmd, itemNames) + }, + } mgmtclassReportCmd.Flags().String("name", "", "the mgmtclass name") + return mgmtclassReportCmd } diff --git a/cmd/mkloaders.go b/cmd/mkloaders.go index c3ce785..1144494 100644 --- a/cmd/mkloaders.go +++ b/cmd/mkloaders.go @@ -9,29 +9,28 @@ import ( "github.com/spf13/cobra" ) -// mkloadersCmd represents the mkloaders command -var mkloadersCmd = &cobra.Command{ - Use: "mkloaders", - Short: "Generate GRUB 2 bootloaders", - Long: `Generate UEFI bootable GRUB 2 bootloaders. If available on the operating system Cobbler is running on, +// NewMkLoadersCmd builds a new command that represents the mkloaders action +func NewMkLoadersCmd() *cobra.Command { + mkloadersCmd := &cobra.Command{ + Use: "mkloaders", + Short: "Generate GRUB 2 bootloaders", + Long: `Generate UEFI bootable GRUB 2 bootloaders. If available on the operating system Cobbler is running on, then this also generates bootloaders for different architectures then the one of the system. The options are configured in the Cobbler settings file.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - eventId, err := Client.BackgroundMkLoaders() - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) - return nil - }, -} - -func init() { - rootCmd.AddCommand(mkloadersCmd) + eventId, err := Client.BackgroundMkLoaders() + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil + }, + } + return mkloadersCmd } diff --git a/cmd/package.go b/cmd/package.go index 12941b0..10eaed5 100644 --- a/cmd/package.go +++ b/cmd/package.go @@ -71,214 +71,266 @@ func updatePackageFromFlags(cmd *cobra.Command, p *cobbler.Package) error { return err } -// packageCmd represents the package command -var packageCmd = &cobra.Command{ - Use: "package", - Short: "Package management", - Long: `Let you manage packages. +// NewPackageCmd builds a new command that represents the package action +func NewPackageCmd() *cobra.Command { + packageCmd := &cobra.Command{ + Use: "package", + Short: "Package management", + Long: `Let you manage packages. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-package for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + packageCmd.AddCommand(NewPackageAddCmd()) + packageCmd.AddCommand(NewPackageCopyCmd()) + packageCmd.AddCommand(NewPackageEditCmd()) + packageCmd.AddCommand(NewPackageFindCmd()) + packageCmd.AddCommand(NewPackageListCmd()) + packageCmd.AddCommand(NewPackageRemoveCmd()) + packageCmd.AddCommand(NewPackageRenameCmd()) + packageCmd.AddCommand(NewPackageReportCmd()) + return packageCmd } -var packageAddCmd = &cobra.Command{ - Use: "add", - Short: "add package", - Long: `Adds a package.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewPackageAddCmd() *cobra.Command { + packageAddCmd := &cobra.Command{ + Use: "add", + Short: "add package", + Long: `Adds a package.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - newPackage := cobbler.NewPackage() + newPackage := cobbler.NewPackage() - // internal fields (ctime, mtime, depth, uid) cannot be modified - newPackage.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - // Update package in-memory - err = updatePackageFromFlags(cmd, &newPackage) - if err != nil { - return err - } - // Create package via XML-RPC - linuxpackage, err := Client.CreatePackage(newPackage) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Package %s created\n", linuxpackage.Name) - return nil - }, + // internal fields (ctime, mtime, depth, uid) cannot be modified + newPackage.Name, err = cmd.Flags().GetString("name") + if err != nil { + return err + } + // Update package in-memory + err = updatePackageFromFlags(cmd, &newPackage) + if err != nil { + return err + } + // Create package via XML-RPC + linuxpackage, err := Client.CreatePackage(newPackage) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Package %s created\n", linuxpackage.Name) + return nil + }, + } + addCommonArgs(packageAddCmd) + addStringFlags(packageAddCmd, packageStringFlagMetadata) + return packageAddCmd } -var packageCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy package", - Long: `Copies a package.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewPackageCopyCmd() *cobra.Command { + packageCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy package", + Long: `Copies a package.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // Collect CLI flags - packageName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - packageNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } + // Collect CLI flags + packageName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + packageNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // Get package handle - packageHandle, err := Client.GetPackageHandle(packageName) - if err != nil { - return err - } - // Copy the package server-side - err = Client.CopyPackage(packageHandle, packageNewName) - if err != nil { - return err - } - // Get the copied package from the API - newPackage, err := Client.GetPackage(packageNewName, false, false) - if err != nil { - return err - } - // Update package in-memory - err = updatePackageFromFlags(cmd, newPackage) - if err != nil { - return err - } - // Update the package via XML-RPC - return Client.UpdatePackage(newPackage) - }, + // Get package handle + packageHandle, err := Client.GetPackageHandle(packageName) + if err != nil { + return err + } + // Copy the package server-side + err = Client.CopyPackage(packageHandle, packageNewName) + if err != nil { + return err + } + // Get the copied package from the API + newPackage, err := Client.GetPackage(packageNewName, false, false) + if err != nil { + return err + } + // Update package in-memory + err = updatePackageFromFlags(cmd, newPackage) + if err != nil { + return err + } + // Update the package via XML-RPC + return Client.UpdatePackage(newPackage) + }, + } + addCommonArgs(packageCopyCmd) + addStringFlags(packageCopyCmd, packageStringFlagMetadata) + packageCopyCmd.Flags().String("newname", "", "the new package name") + packageCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return packageCopyCmd } -var packageEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit package", - Long: `Edits a package.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewPackageEditCmd() *cobra.Command { + packageEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit package", + Long: `Edits a package.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - packageName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } + packageName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } - // Get package from the API - packageToEdit, err := Client.GetPackage(packageName, false, false) - if err != nil { - return err - } - // Update package in-memory - err = updatePackageFromFlags(cmd, packageToEdit) - if err != nil { - return err - } - // Update package via XML-RPC - return Client.UpdatePackage(packageToEdit) - }, + // Get package from the API + packageToEdit, err := Client.GetPackage(packageName, false, false) + if err != nil { + return err + } + // Update package in-memory + err = updatePackageFromFlags(cmd, packageToEdit) + if err != nil { + return err + } + // Update package via XML-RPC + return Client.UpdatePackage(packageToEdit) + }, + } + addCommonArgs(packageEditCmd) + addStringFlags(packageEditCmd, packageStringFlagMetadata) + packageEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return packageEditCmd } -var packageFindCmd = &cobra.Command{ - Use: "find", - Short: "find package", - Long: `Finds a given package.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewPackageFindCmd() *cobra.Command { + packageFindCmd := &cobra.Command{ + Use: "find", + Short: "find package", + Long: `Finds a given package.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - return FindItemNames(cmd, args, "package") - }, + return FindItemNames(cmd, args, "package") + }, + } + addCommonArgs(packageFindCmd) + addStringFlags(packageFindCmd, packageStringFlagMetadata) + addStringFlags(packageFindCmd, findStringFlagMetadata) + addIntFlags(packageFindCmd, findIntFlagMetadata) + addFloatFlags(packageFindCmd, findFloatFlagMetadata) + return packageFindCmd } -var packageListCmd = &cobra.Command{ - Use: "list", - Short: "list all packages", - Long: `Lists all available packages.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewPackageListCmd() *cobra.Command { + packageListCmd := &cobra.Command{ + Use: "list", + Short: "list all packages", + Long: `Lists all available packages.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - packageNames, err := Client.ListPackageNames() - if err != nil { - return err - } - listItems(cmd, "packages", packageNames) - return nil - }, + packageNames, err := Client.ListPackageNames() + if err != nil { + return err + } + listItems(cmd, "packages", packageNames) + return nil + }, + } + return packageListCmd } -var packageRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove package", - Long: `Removes a given package.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewPackageRemoveCmd() *cobra.Command { + packageRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove package", + Long: `Removes a given package.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - return RemoveItemRecursive(cmd, args, "package") - }, + return RemoveItemRecursive(cmd, args, "package") + }, + } + packageRemoveCmd.Flags().String("name", "", "the package name") + packageRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return packageRemoveCmd } -var packageRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename package", - Long: `Renames a given package.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewPackageRenameCmd() *cobra.Command { + packageRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename package", + Long: `Renames a given package.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // internal fields (ctime, mtime, depth, uid) cannot be modified - packageName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - packageNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } + // internal fields (ctime, mtime, depth, uid) cannot be modified + packageName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + packageNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // Get package API handle - packageHandle, err := Client.GetPackageHandle(packageName) - if err != nil { - return err - } - // Perform server-side package rename - err = Client.RenamePackage(packageHandle, packageNewName) - if err != nil { - return err - } - // Get the renamed package from the API - newPackage, err := Client.GetPackage(packageNewName, false, false) - if err != nil { - return err - } - // Update package in-memory - err = updatePackageFromFlags(cmd, newPackage) - if err != nil { - return err - } - // Update package via XML-RPC - return Client.UpdatePackage(newPackage) - }, + // Get package API handle + packageHandle, err := Client.GetPackageHandle(packageName) + if err != nil { + return err + } + // Perform server-side package rename + err = Client.RenamePackage(packageHandle, packageNewName) + if err != nil { + return err + } + // Get the renamed package from the API + newPackage, err := Client.GetPackage(packageNewName, false, false) + if err != nil { + return err + } + // Update package in-memory + err = updatePackageFromFlags(cmd, newPackage) + if err != nil { + return err + } + // Update package via XML-RPC + return Client.UpdatePackage(newPackage) + }, + } + addCommonArgs(packageRenameCmd) + addStringFlags(packageRenameCmd, packageStringFlagMetadata) + packageRenameCmd.Flags().String("newname", "", "the new package name") + packageRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return packageRenameCmd } func reportPackages(cmd *cobra.Command, packageNames []string) error { @@ -293,76 +345,33 @@ func reportPackages(cmd *cobra.Command, packageNames []string) error { return nil } -var packageReportCmd = &cobra.Command{ - Use: "report", - Short: "list all packages in detail", - Long: `Shows detailed information about all packages.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListRepoNames() +func NewPackageReportCmd() *cobra.Command { + packageReportCmd := &cobra.Command{ + Use: "report", + Short: "list all packages in detail", + Long: `Shows detailed information about all packages.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - } else { - itemNames = append(itemNames, name) - } - return reportPackages(cmd, itemNames) - }, -} -func init() { - rootCmd.AddCommand(packageCmd) - packageCmd.AddCommand(packageAddCmd) - packageCmd.AddCommand(packageCopyCmd) - packageCmd.AddCommand(packageEditCmd) - packageCmd.AddCommand(packageFindCmd) - packageCmd.AddCommand(packageListCmd) - packageCmd.AddCommand(packageRemoveCmd) - packageCmd.AddCommand(packageRenameCmd) - packageCmd.AddCommand(packageReportCmd) - - // local flags for package add - addCommonArgs(packageAddCmd) - addStringFlags(packageAddCmd, packageStringFlagMetadata) - - // local flags for package copy - addCommonArgs(packageCopyCmd) - addStringFlags(packageCopyCmd, packageStringFlagMetadata) - packageCopyCmd.Flags().String("newname", "", "the new package name") - packageCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") - - // local flags for package edit - addCommonArgs(packageEditCmd) - addStringFlags(packageEditCmd, packageStringFlagMetadata) - packageEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") - - // local flags for package find - addCommonArgs(packageFindCmd) - addStringFlags(packageFindCmd, packageStringFlagMetadata) - addStringFlags(packageFindCmd, findStringFlagMetadata) - addIntFlags(packageFindCmd, findIntFlagMetadata) - addFloatFlags(packageFindCmd, findFloatFlagMetadata) - - // local flags for package remove - packageRemoveCmd.Flags().String("name", "", "the package name") - packageRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") - - // local flags for package rename - addCommonArgs(packageRenameCmd) - addStringFlags(packageRenameCmd, packageStringFlagMetadata) - packageRenameCmd.Flags().String("newname", "", "the new package name") - packageRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") - - // local flags for package report + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListRepoNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportPackages(cmd, itemNames) + }, + } packageReportCmd.Flags().String("name", "", "the package name") + return packageReportCmd } diff --git a/cmd/profile.go b/cmd/profile.go index da9c01b..6f0529f 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -505,320 +505,59 @@ func updateProfileFromFlags(cmd *cobra.Command, profile *cobbler.Profile) error return nil } -// profileCmd represents the profile command -var profileCmd = &cobra.Command{ - Use: "profile", - Short: "Profile management", - Long: `Let you manage profiles. +// NewProfileCmd builds a new command that represents the profile action +func NewProfileCmd() *cobra.Command { + profileCmd := &cobra.Command{ + Use: "profile", + Short: "Profile management", + Long: `Let you manage profiles. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-profile for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, -} - -var profileAddCmd = &cobra.Command{ - Use: "add", - Short: "add profile", - Long: `Adds a profile.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - newProfile := cobbler.NewProfile() - // internal fields (ctime, mtime, uid, depth, repos-enabled) cannot be modified - newProfile.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - err = updateProfileFromFlags(cmd, &newProfile) - if err != nil { - return err - } - profile, err := Client.CreateProfile(newProfile) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Profile %s created\n", profile.Name) - return nil - }, -} - -var profileCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy profile", - Long: `Copies a profile.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - profileName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - profileNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - profileHandle, err := Client.GetProfileHandle(profileName) - if err != nil { - return err - } - err = Client.CopyDistro(profileHandle, profileNewName) - if err != nil { - return err - } - newProfile, err := Client.GetProfile(profileNewName, false, false) - if err != nil { - return err - } - err = updateProfileFromFlags(cmd, newProfile) - if err != nil { - return err - } - return Client.UpdateProfile(newProfile) - }, -} - -var profileDumpVarsCmd = &cobra.Command{ - Use: "dumpvars", - Short: "dump profile variables", - Long: `Prints all profile variables to stdout.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get CLI flags - profileName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - - // Now retrieve data - blendedData, err := Client.GetBlendedData(profileName, "") - if err != nil { - return err - } - // Print data - printDumpVars(cmd, blendedData) - return err - }, -} - -var profileEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit profile", - Long: `Edits a profile.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // find profile through its name - pname, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - updateProfile, err := Client.GetProfile(pname, false, false) - if err != nil { - return err - } - - // internal fields (ctime, mtime, uid, depth, repos-enabled) cannot be modified - err = updateProfileFromFlags(cmd, updateProfile) - if err != nil { - return err - } - return Client.UpdateProfile(updateProfile) - }, -} - -var profileFindCmd = &cobra.Command{ - Use: "find", - Short: "find profile", - Long: `Finds a given profile.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return FindItemNames(cmd, args, "profile") - }, -} - -var profileGetAutoinstallCmd = &cobra.Command{ - Use: "get-autoinstall", - Short: "dump autoinstall XML", - Long: `Prints the autoinstall XML file of the given profile to stdout.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - profileName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - profileExists, err := Client.HasItem("profile", profileName) - if err != nil { - return err - } - if !profileExists { - return fmt.Errorf("Profile does not exist!") - - } - autoinstallRendered, err := Client.GenerateAutoinstall(profileName, "") - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), autoinstallRendered) - return nil - }, -} - -var profileListCmd = &cobra.Command{ - Use: "list", - Short: "list all profiles", - Long: `Lists all available profiles.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - profileNames, err := Client.ListProfileNames() - if err != nil { - return err - } - listItems(cmd, "profiles", profileNames) - return nil - }, -} - -var profileRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove profile", - Long: `Removes a given profile.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - pname, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - recursiveDelete, err := cmd.Flags().GetBool("recursive") - if err != nil { - return err - } - return Client.DeleteProfileRecursive(pname, recursiveDelete) - }, -} - -var profileRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename profile", - Long: `Renames a given profile.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - profileName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - profileNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - // Now do the real edit - profileHandle, err := Client.GetProfileHandle(profileName) - if err != nil { - return err - } - err = Client.RenameProfile(profileHandle, profileNewName) - if err != nil { - return err - } - newProfile, err := Client.GetProfile(profileNewName, false, false) - if err != nil { - return err - } - err = updateProfileFromFlags(cmd, newProfile) - if err != nil { - return err - } - return Client.UpdateProfile(newProfile) - }, -} - -func reportProfiles(cmd *cobra.Command, profileNames []string) error { - for _, itemName := range profileNames { - profile, err := Client.GetProfile(itemName, false, false) - if err != nil { - return err - } - printStructured(cmd, profile) - fmt.Fprintln(cmd.OutOrStdout(), "") + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, } - return nil + profileCmd.AddCommand(NewProfileAddCmd()) + profileCmd.AddCommand(NewProfileCopyCmd()) + profileCmd.AddCommand(NewProfileDumpVars()) + profileCmd.AddCommand(NewProfileEditCmd()) + profileCmd.AddCommand(NewProfileFindCmd()) + profileCmd.AddCommand(NewProfileGetAutoinstallCmd()) + profileCmd.AddCommand(NewProfileListCmd()) + profileCmd.AddCommand(NewProfileRemoveCmd()) + profileCmd.AddCommand(NewProfileRenameCmd()) + profileCmd.AddCommand(NewProfileReportCmd()) + return profileCmd } -var profileReportCmd = &cobra.Command{ - Use: "report", - Short: "list all profiles in detail", - Long: `Shows detailed information about all profiles.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListProfileNames() +func NewProfileAddCmd() *cobra.Command { + profileAddCmd := &cobra.Command{ + Use: "add", + Short: "add profile", + Long: `Adds a profile.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - } else { - itemNames = append(itemNames, name) - } - return reportProfiles(cmd, itemNames) - }, -} - -func init() { - rootCmd.AddCommand(profileCmd) - profileCmd.AddCommand(profileAddCmd) - profileCmd.AddCommand(profileCopyCmd) - profileCmd.AddCommand(profileDumpVarsCmd) - profileCmd.AddCommand(profileEditCmd) - profileCmd.AddCommand(profileFindCmd) - profileCmd.AddCommand(profileGetAutoinstallCmd) - profileCmd.AddCommand(profileListCmd) - profileCmd.AddCommand(profileRemoveCmd) - profileCmd.AddCommand(profileRenameCmd) - profileCmd.AddCommand(profileReportCmd) - // local flags for profile add + newProfile := cobbler.NewProfile() + // internal fields (ctime, mtime, uid, depth, repos-enabled) cannot be modified + newProfile.Name, err = cmd.Flags().GetString("name") + if err != nil { + return err + } + err = updateProfileFromFlags(cmd, &newProfile) + if err != nil { + return err + } + profile, err := Client.CreateProfile(newProfile) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Profile %s created\n", profile.Name) + return nil + }, + } addCommonArgs(profileAddCmd) addStringFlags(profileAddCmd, profileStringFlagMetadata) addBoolFlags(profileAddCmd, profileBoolFlagMetadata) @@ -829,8 +568,48 @@ func init() { addMapFlags(profileAddCmd, distroMapFlagMetadata) addMapFlags(profileAddCmd, profileMapFlagMetadata) profileAddCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return profileAddCmd +} + +func NewProfileCopyCmd() *cobra.Command { + profileCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy profile", + Long: `Copies a profile.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + profileName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + profileNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // local flags for profile copy + profileHandle, err := Client.GetProfileHandle(profileName) + if err != nil { + return err + } + err = Client.CopyDistro(profileHandle, profileNewName) + if err != nil { + return err + } + newProfile, err := Client.GetProfile(profileNewName, false, false) + if err != nil { + return err + } + err = updateProfileFromFlags(cmd, newProfile) + if err != nil { + return err + } + return Client.UpdateProfile(newProfile) + }, + } addCommonArgs(profileCopyCmd) addStringFlags(profileCopyCmd, profileStringFlagMetadata) addBoolFlags(profileCopyCmd, profileBoolFlagMetadata) @@ -842,11 +621,69 @@ func init() { addMapFlags(profileCopyCmd, profileMapFlagMetadata) profileCopyCmd.Flags().String("newname", "", "the new profile name") profileCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return profileCopyCmd +} + +func NewProfileDumpVars() *cobra.Command { + profileDumpVarsCmd := &cobra.Command{ + Use: "dumpvars", + Short: "dump profile variables", + Long: `Prints all profile variables to stdout.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for profile dumpvars + // Get CLI flags + profileName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + + // Now retrieve data + blendedData, err := Client.GetBlendedData(profileName, "") + if err != nil { + return err + } + // Print data + printDumpVars(cmd, blendedData) + return err + }, + } profileDumpVarsCmd.Flags().String("name", "", "the profile name") + return profileDumpVarsCmd +} + +func NewProfileEditCmd() *cobra.Command { + profileEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit profile", + Long: `Edits a profile.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // find profile through its name + pname, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + updateProfile, err := Client.GetProfile(pname, false, false) + if err != nil { + return err + } - // local flags for profile edit + // internal fields (ctime, mtime, uid, depth, repos-enabled) cannot be modified + err = updateProfileFromFlags(cmd, updateProfile) + if err != nil { + return err + } + return Client.UpdateProfile(updateProfile) + }, + } addCommonArgs(profileEditCmd) addStringFlags(profileEditCmd, profileStringFlagMetadata) addBoolFlags(profileEditCmd, profileBoolFlagMetadata) @@ -857,8 +694,23 @@ func init() { addMapFlags(profileEditCmd, distroMapFlagMetadata) addMapFlags(profileEditCmd, profileMapFlagMetadata) profileEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return profileEditCmd +} + +func NewProfileFindCmd() *cobra.Command { + profileFindCmd := &cobra.Command{ + Use: "find", + Short: "find profile", + Long: `Finds a given profile.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for profile find + return FindItemNames(cmd, args, "profile") + }, + } addCommonArgs(profileFindCmd) addStringFlags(profileFindCmd, profileStringFlagMetadata) addBoolFlags(profileFindCmd, profileBoolFlagMetadata) @@ -871,15 +723,133 @@ func init() { addStringFlags(profileFindCmd, findStringFlagMetadata) addIntFlags(profileFindCmd, findIntFlagMetadata) addFloatFlags(profileFindCmd, findFloatFlagMetadata) + return profileFindCmd +} + +func NewProfileGetAutoinstallCmd() *cobra.Command { + profileGetAutoinstallCmd := &cobra.Command{ + Use: "get-autoinstall", + Short: "dump autoinstall XML", + Long: `Prints the autoinstall XML file of the given profile to stdout.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + profileName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + profileExists, err := Client.HasItem("profile", profileName) + if err != nil { + return err + } + if !profileExists { + return fmt.Errorf("Profile does not exist!") - // local flags for profile get-autoinstall + } + autoinstallRendered, err := Client.GenerateAutoinstall(profileName, "") + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), autoinstallRendered) + return nil + }, + } profileGetAutoinstallCmd.Flags().String("name", "", "the profile name") + return profileGetAutoinstallCmd +} + +func NewProfileListCmd() *cobra.Command { + profileListCmd := &cobra.Command{ + Use: "list", + Short: "list all profiles", + Long: `Lists all available profiles.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + profileNames, err := Client.ListProfileNames() + if err != nil { + return err + } + listItems(cmd, "profiles", profileNames) + return nil + }, + } + return profileListCmd +} + +func NewProfileRemoveCmd() *cobra.Command { + profileRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove profile", + Long: `Removes a given profile.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for profile remove + pname, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + recursiveDelete, err := cmd.Flags().GetBool("recursive") + if err != nil { + return err + } + return Client.DeleteProfileRecursive(pname, recursiveDelete) + }, + } profileRemoveCmd.Flags().String("name", "", "the profile name") profileRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return profileRemoveCmd +} + +func NewProfileRenameCmd() *cobra.Command { + profileRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename profile", + Long: `Renames a given profile.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + profileName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + profileNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // local flags for profile rename + // Now do the real edit + profileHandle, err := Client.GetProfileHandle(profileName) + if err != nil { + return err + } + err = Client.RenameProfile(profileHandle, profileNewName) + if err != nil { + return err + } + newProfile, err := Client.GetProfile(profileNewName, false, false) + if err != nil { + return err + } + err = updateProfileFromFlags(cmd, newProfile) + if err != nil { + return err + } + return Client.UpdateProfile(newProfile) + }, + } addCommonArgs(profileRenameCmd) addStringFlags(profileRenameCmd, profileStringFlagMetadata) addBoolFlags(profileRenameCmd, profileBoolFlagMetadata) @@ -891,7 +861,48 @@ func init() { addMapFlags(profileRenameCmd, profileMapFlagMetadata) profileRenameCmd.Flags().String("newname", "", "the new profile name") profileRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return profileRenameCmd +} + +func reportProfiles(cmd *cobra.Command, profileNames []string) error { + for _, itemName := range profileNames { + profile, err := Client.GetProfile(itemName, false, false) + if err != nil { + return err + } + printStructured(cmd, profile) + fmt.Fprintln(cmd.OutOrStdout(), "") + } + return nil +} + +func NewProfileReportCmd() *cobra.Command { + profileReportCmd := &cobra.Command{ + Use: "report", + Short: "list all profiles in detail", + Long: `Shows detailed information about all profiles.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for profile report + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListProfileNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportProfiles(cmd, itemNames) + }, + } profileReportCmd.Flags().String("name", "", "the profile name") + return profileReportCmd } diff --git a/cmd/replicate.go b/cmd/replicate.go index 11d6683..5ff6ee0 100644 --- a/cmd/replicate.go +++ b/cmd/replicate.go @@ -10,107 +10,103 @@ import ( "github.com/spf13/cobra" ) -// replicateCmd represents the replicate command -var replicateCmd = &cobra.Command{ - Use: "replicate", - Short: "Replicate data", - Long: `Replicate configurations from a master Cobbler server. This feature is intended for load-balancing, +// NewReplicateCmd builds a new command that represents the replicate action +func NewReplicateCmd() *cobra.Command { + replicateCmd := &cobra.Command{ + Use: "replicate", + Short: "Replicate data", + Long: `Replicate configurations from a master Cobbler server. This feature is intended for load-balancing, disaster-recovery, backup, or multiple geography support. Each Cobbler server is still expected to have a locally relevant cobbler.conf and modules.conf, as these files are not synced. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-replicate for more information.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - distrosOption, err := cmd.Flags().GetString("distros") - if err != nil { - return err - } - profilesOption, err := cmd.Flags().GetString("profiles") - if err != nil { - return err - } - systemsOption, err := cmd.Flags().GetString("systems") - if err != nil { - return err - } - reposOption, err := cmd.Flags().GetString("repos") - if err != nil { - return err - } - imagesOption, err := cmd.Flags().GetString("image") - if err != nil { - return err - } - mgmtClassesOption, err := cmd.Flags().GetString("mgmtclasses") - if err != nil { - return err - } - packagesOption, err := cmd.Flags().GetString("packages") - if err != nil { - return err - } - filesOption, err := cmd.Flags().GetString("files") - if err != nil { - return err - } - portOption, err := cmd.Flags().GetString("port") - if err != nil { - return err - } - masterOption, err := cmd.Flags().GetString("master") - if err != nil { - return err - } - pruneOption, err := cmd.Flags().GetBool("prune") - if err != nil { - return err - } - omitDataOption, err := cmd.Flags().GetBool("omit-data") - if err != nil { - return err - } - syncAllOption, err := cmd.Flags().GetBool("sync-all") - if err != nil { - return err - } - useSslOption, err := cmd.Flags().GetBool("use-ssl") - if err != nil { - return err - } - replicateOptions := cobblerclient.ReplicateOptions{ - Master: masterOption, - Port: portOption, - DistroPatterns: distrosOption, - ProfilePatterns: profilesOption, - SystemPatterns: systemsOption, - RepoPatterns: reposOption, - Imagepatterns: imagesOption, - MgmtclassPatterns: mgmtClassesOption, - PackagePatterns: packagesOption, - FilePatterns: filesOption, - Prune: pruneOption, - OmitData: omitDataOption, - SyncAll: syncAllOption, - UseSsl: useSslOption, - } - eventId, err := Client.BackgroundReplicate(replicateOptions) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "EventID: %s\n", eventId) - return nil - }, -} - -func init() { - rootCmd.AddCommand(replicateCmd) - - //local flags + distrosOption, err := cmd.Flags().GetString("distros") + if err != nil { + return err + } + profilesOption, err := cmd.Flags().GetString("profiles") + if err != nil { + return err + } + systemsOption, err := cmd.Flags().GetString("systems") + if err != nil { + return err + } + reposOption, err := cmd.Flags().GetString("repos") + if err != nil { + return err + } + imagesOption, err := cmd.Flags().GetString("image") + if err != nil { + return err + } + mgmtClassesOption, err := cmd.Flags().GetString("mgmtclasses") + if err != nil { + return err + } + packagesOption, err := cmd.Flags().GetString("packages") + if err != nil { + return err + } + filesOption, err := cmd.Flags().GetString("files") + if err != nil { + return err + } + portOption, err := cmd.Flags().GetString("port") + if err != nil { + return err + } + masterOption, err := cmd.Flags().GetString("master") + if err != nil { + return err + } + pruneOption, err := cmd.Flags().GetBool("prune") + if err != nil { + return err + } + omitDataOption, err := cmd.Flags().GetBool("omit-data") + if err != nil { + return err + } + syncAllOption, err := cmd.Flags().GetBool("sync-all") + if err != nil { + return err + } + useSslOption, err := cmd.Flags().GetBool("use-ssl") + if err != nil { + return err + } + replicateOptions := cobblerclient.ReplicateOptions{ + Master: masterOption, + Port: portOption, + DistroPatterns: distrosOption, + ProfilePatterns: profilesOption, + SystemPatterns: systemsOption, + RepoPatterns: reposOption, + Imagepatterns: imagesOption, + MgmtclassPatterns: mgmtClassesOption, + PackagePatterns: packagesOption, + FilePatterns: filesOption, + Prune: pruneOption, + OmitData: omitDataOption, + SyncAll: syncAllOption, + UseSsl: useSslOption, + } + eventId, err := Client.BackgroundReplicate(replicateOptions) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "EventID: %s\n", eventId) + return nil + }, + } replicateCmd.Flags().String("distros", "", "patterns of distros to replicate") replicateCmd.Flags().String("files", "", "patterns of files to replicate") replicateCmd.Flags().String("image", "", "patterns of images to replicate") @@ -125,4 +121,5 @@ func init() { replicateCmd.Flags().Bool("sync-all", false, "sync all data") replicateCmd.Flags().String("systems", "", "patterns of systems to replicate") replicateCmd.Flags().Bool("use-ssl", false, "use SSL to access the Cobbler master server API") + return replicateCmd } diff --git a/cmd/repo.go b/cmd/repo.go index 1e7ee1c..bfd74ed 100644 --- a/cmd/repo.go +++ b/cmd/repo.go @@ -170,286 +170,126 @@ func updateRepoFromFlags(cmd *cobra.Command, repo *cobbler.Repo) error { return err } -// repoCmd represents the repo command -var repoCmd = &cobra.Command{ - Use: "repo", - Short: "Repository management", - Long: `Let you manage repositories. +// NewRepoCmd builds a new command that represents the repo action +func NewRepoCmd() *cobra.Command { + repoCmd := &cobra.Command{ + Use: "repo", + Short: "Repository management", + Long: `Let you manage repositories. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-repo for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, -} - -var repoAddCmd = &cobra.Command{ - Use: "add", - Short: "add repository", - Long: `Adds a repository.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - newRepo := cobbler.NewRepo() - - // internal fields (ctime, mtime, depth, uid, parent, tree-build-time) cannot be modified - newRepo.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - // Update repo in-memory - err = updateRepoFromFlags(cmd, &newRepo) - if err != nil { - return err - } - // Now create via XML-RPC - repo, err := Client.CreateRepo(newRepo) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Repo %s created\n", repo.Name) - return nil - }, -} - -var repoAutoAddCmd = &cobra.Command{ - Use: "autoadd", - Short: "add repository automatically", - Long: `Automatically adds a repository.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return Client.AutoAddRepos() - }, -} - -var repoCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy repository", - Long: `Copies a repository.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - repoName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - repoNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - repoHandle, err := Client.GetRepoHandle(repoName) - if err != nil { - return err - } - err = Client.CopyRepo(repoHandle, repoNewName) - if err != nil { - return err - } - copiedRepo, err := Client.GetRepo(repoNewName, false, false) - if err != nil { - return err - } - err = updateRepoFromFlags(cmd, copiedRepo) - if err != nil { - return err - } - return Client.UpdateRepo(copiedRepo) - }, -} - -var repoEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit repository", - Long: `Edits a repository.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // find repo through its name - rname, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - // Get repo from API - updateRepo, err := Client.GetRepo(rname, false, false) - if err != nil { - return err - } - // Update repo in-memory - err = updateRepoFromFlags(cmd, updateRepo) - if err != nil { - return err - } - // Update repo via XML-RPC - return Client.UpdateRepo(updateRepo) - }, -} - -var repoFindCmd = &cobra.Command{ - Use: "find", - Short: "find repository", - Long: `Finds a given repository.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return FindItemNames(cmd, args, "repo") - }, -} - -var repoListCmd = &cobra.Command{ - Use: "list", - Short: "list all repositorys", - Long: `Lists all available repositories.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - repoNames, err := Client.ListRepoNames() - if err != nil { - return err - } - listItems(cmd, "repos", repoNames) - return nil - }, -} - -var repoRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove repository", - Long: `Removes a given repository.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return RemoveItemRecursive(cmd, args, "repo") - }, -} - -var repoRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename repository", - Long: `Renames a given repository.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get special name and newname flags - repoName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - repoNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - // Get repo handle from the API - repoHandle, err := Client.GetMenuHandle(repoName) - if err != nil { - return err - } - // Rename the repo server side - err = Client.RenameRepo(repoHandle, repoNewName) - if err != nil { - return err - } - // Get the renamed repository from the API - newRepository, err := Client.GetRepo(repoNewName, false, false) - if err != nil { - return err - } - // Update the repo in-memory - err = updateRepoFromFlags(cmd, newRepository) - if err != nil { - return err - } - // Update the repo via XML-RPC - return Client.UpdateRepo(newRepository) - }, -} - -func reportRepos(cmd *cobra.Command, repoNames []string) error { - for _, itemName := range repoNames { - repo, err := Client.GetRepo(itemName, false, false) - if err != nil { - return err - } - printStructured(cmd, repo) - fmt.Fprintln(cmd.OutOrStdout(), "") + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, } - return nil + repoCmd.AddCommand(NewRepoAddCmd()) + repoCmd.AddCommand(NewRepoAutoAddCmd()) + repoCmd.AddCommand(NewRepoCopyCmd()) + repoCmd.AddCommand(NewRepoEditCmd()) + repoCmd.AddCommand(NewRepoFindCmd()) + repoCmd.AddCommand(NewRepoListCmd()) + repoCmd.AddCommand(NewRepoRemoveCmd()) + repoCmd.AddCommand(NewRepoRenameCmd()) + repoCmd.AddCommand(NewRepoReportCmd()) + return repoCmd } -var repoReportCmd = &cobra.Command{ - Use: "report", - Short: "list all repositorys in detail", - Long: `Shows detailed information about all repositories.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListRepoNames() +func NewRepoAddCmd() *cobra.Command { + repoAddCmd := &cobra.Command{ + Use: "add", + Short: "add repository", + Long: `Adds a repository.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - } else { - itemNames = append(itemNames, name) - } - return reportRepos(cmd, itemNames) - }, -} -func init() { - rootCmd.AddCommand(repoCmd) - repoCmd.AddCommand(repoAddCmd) - repoCmd.AddCommand(repoAutoAddCmd) - repoCmd.AddCommand(repoCopyCmd) - repoCmd.AddCommand(repoEditCmd) - repoCmd.AddCommand(repoFindCmd) - repoCmd.AddCommand(repoListCmd) - repoCmd.AddCommand(repoRemoveCmd) - repoCmd.AddCommand(repoRenameCmd) - repoCmd.AddCommand(repoReportCmd) + newRepo := cobbler.NewRepo() - // local flags for repo add + // internal fields (ctime, mtime, depth, uid, parent, tree-build-time) cannot be modified + newRepo.Name, err = cmd.Flags().GetString("name") + if err != nil { + return err + } + // Update repo in-memory + err = updateRepoFromFlags(cmd, &newRepo) + if err != nil { + return err + } + // Now create via XML-RPC + repo, err := Client.CreateRepo(newRepo) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Repo %s created\n", repo.Name) + return nil + }, + } addCommonArgs(repoAddCmd) addStringFlags(repoAddCmd, repoStringFlagMetadata) addBoolFlags(repoAddCmd, repoBoolFlagMetadata) addIntFlags(repoAddCmd, repoIntFlagMetadata) addStringSliceFlags(repoAddCmd, repoStringSliceFlagMetadata) addMapFlags(repoAddCmd, repoMapFlagMetadata) + return repoAddCmd +} + +func NewRepoAutoAddCmd() *cobra.Command { + repoAutoAddCmd := &cobra.Command{ + Use: "autoadd", + Short: "add repository automatically", + Long: `Automatically adds a repository.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + return Client.AutoAddRepos() + }, + } + return repoAutoAddCmd +} + +func NewRepoCopyCmd() *cobra.Command { + repoCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy repository", + Long: `Copies a repository.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for repo autoadd - // no flags + repoName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + repoNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } - // local flags for repo copy + repoHandle, err := Client.GetRepoHandle(repoName) + if err != nil { + return err + } + err = Client.CopyRepo(repoHandle, repoNewName) + if err != nil { + return err + } + copiedRepo, err := Client.GetRepo(repoNewName, false, false) + if err != nil { + return err + } + err = updateRepoFromFlags(cmd, copiedRepo) + if err != nil { + return err + } + return Client.UpdateRepo(copiedRepo) + }, + } addCommonArgs(repoCopyCmd) addStringFlags(repoCopyCmd, repoStringFlagMetadata) addBoolFlags(repoCopyCmd, repoBoolFlagMetadata) @@ -458,8 +298,39 @@ func init() { addMapFlags(repoCopyCmd, repoMapFlagMetadata) repoCopyCmd.Flags().String("newname", "", "the new repo name") repoCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return repoCopyCmd +} + +func NewRepoEditCmd() *cobra.Command { + repoEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit repository", + Long: `Edits a repository.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for repo edit + // find repo through its name + rname, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + // Get repo from API + updateRepo, err := Client.GetRepo(rname, false, false) + if err != nil { + return err + } + // Update repo in-memory + err = updateRepoFromFlags(cmd, updateRepo) + if err != nil { + return err + } + // Update repo via XML-RPC + return Client.UpdateRepo(updateRepo) + }, + } addCommonArgs(repoEditCmd) addStringFlags(repoEditCmd, repoStringFlagMetadata) addBoolFlags(repoEditCmd, repoBoolFlagMetadata) @@ -467,8 +338,23 @@ func init() { addStringSliceFlags(repoEditCmd, repoStringSliceFlagMetadata) addMapFlags(repoEditCmd, repoMapFlagMetadata) repoEditCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return repoEditCmd +} + +func NewRepoFindCmd() *cobra.Command { + repoFindCmd := &cobra.Command{ + Use: "find", + Short: "find repository", + Long: `Finds a given repository.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for repo find + return FindItemNames(cmd, args, "repo") + }, + } addCommonArgs(repoFindCmd) addStringFlags(repoFindCmd, repoStringFlagMetadata) addBoolFlags(repoFindCmd, repoBoolFlagMetadata) @@ -479,12 +365,94 @@ func init() { addIntFlags(repoFindCmd, findIntFlagMetadata) addFloatFlags(repoFindCmd, findFloatFlagMetadata) repoFindCmd.Flags().String("parent", "", "") + return repoFindCmd +} - // local flags for repo remove +func NewRepoListCmd() *cobra.Command { + repoListCmd := &cobra.Command{ + Use: "list", + Short: "list all repositorys", + Long: `Lists all available repositories.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + repoNames, err := Client.ListRepoNames() + if err != nil { + return err + } + listItems(cmd, "repos", repoNames) + return nil + }, + } + return repoListCmd +} + +func NewRepoRemoveCmd() *cobra.Command { + repoRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove repository", + Long: `Removes a given repository.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + return RemoveItemRecursive(cmd, args, "repo") + }, + } repoRemoveCmd.Flags().String("name", "", "the repo name") repoRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return repoRemoveCmd +} + +func NewRepoRenameCmd() *cobra.Command { + repoRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename repository", + Long: `Renames a given repository.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for repo rename + // Get special name and newname flags + repoName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + repoNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } + // Get repo handle from the API + repoHandle, err := Client.GetMenuHandle(repoName) + if err != nil { + return err + } + // Rename the repo server side + err = Client.RenameRepo(repoHandle, repoNewName) + if err != nil { + return err + } + // Get the renamed repository from the API + newRepository, err := Client.GetRepo(repoNewName, false, false) + if err != nil { + return err + } + // Update the repo in-memory + err = updateRepoFromFlags(cmd, newRepository) + if err != nil { + return err + } + // Update the repo via XML-RPC + return Client.UpdateRepo(newRepository) + }, + } addCommonArgs(repoRenameCmd) addStringFlags(repoRenameCmd, repoStringFlagMetadata) addBoolFlags(repoRenameCmd, repoBoolFlagMetadata) @@ -493,7 +461,48 @@ func init() { addMapFlags(repoRenameCmd, repoMapFlagMetadata) repoRenameCmd.Flags().String("newname", "", "the new repo name") repoRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") + return repoRenameCmd +} - // local flags for repo report +func reportRepos(cmd *cobra.Command, repoNames []string) error { + for _, itemName := range repoNames { + repo, err := Client.GetRepo(itemName, false, false) + if err != nil { + return err + } + printStructured(cmd, repo) + fmt.Fprintln(cmd.OutOrStdout(), "") + } + return nil +} + +func NewRepoReportCmd() *cobra.Command { + repoReportCmd := &cobra.Command{ + Use: "report", + Short: "list all repositorys in detail", + Long: `Shows detailed information about all repositories.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListRepoNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportRepos(cmd, itemNames) + }, + } repoReportCmd.Flags().String("name", "", "the repo name") + return repoReportCmd } diff --git a/cmd/report.go b/cmd/report.go index d0aa36e..a54355f 100644 --- a/cmd/report.go +++ b/cmd/report.go @@ -9,140 +9,139 @@ import ( "github.com/spf13/cobra" ) -// reportCmd represents the report command -var reportCmd = &cobra.Command{ - Use: "report", - Short: "List configuration in detail", - Long: `Lists all configuration which Cobbler can obtain from the saved data. There are also report subcommands for +// NewReportCmd builds a new command that represents the report action +func NewReportCmd() *cobra.Command { + reportCmd := &cobra.Command{ + Use: "report", + Short: "List configuration in detail", + Long: `Lists all configuration which Cobbler can obtain from the saved data. There are also report subcommands for most of the other Cobbler commands (currently: distro, profile, system, repo, image, mgmtclass, package, file, menu). Identical to 'cobbler list'`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // Distro - fmt.Fprintln(cmd.OutOrStdout(), "distros:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - distroNames, err := Client.ListDistroNames() - if err != nil { - return err - } - err = reportDistros(cmd, distroNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") + // Distro + fmt.Fprintln(cmd.OutOrStdout(), "distros:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + distroNames, err := Client.ListDistroNames() + if err != nil { + return err + } + err = reportDistros(cmd, distroNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") - // Profile - fmt.Fprintln(cmd.OutOrStdout(), "profiles:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - profileNames, err := Client.ListProfileNames() - if err != nil { - return err - } - err = reportProfiles(cmd, profileNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") + // Profile + fmt.Fprintln(cmd.OutOrStdout(), "profiles:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + profileNames, err := Client.ListProfileNames() + if err != nil { + return err + } + err = reportProfiles(cmd, profileNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") - // System - fmt.Fprintln(cmd.OutOrStdout(), "systems:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - systemNames, err := Client.ListSystemNames() - if err != nil { - return err - } - err = reportSystems(cmd, systemNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") + // System + fmt.Fprintln(cmd.OutOrStdout(), "systems:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + systemNames, err := Client.ListSystemNames() + if err != nil { + return err + } + err = reportSystems(cmd, systemNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") - // Repository - fmt.Fprintln(cmd.OutOrStdout(), "repos:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - repoNames, err := Client.ListRepoNames() - if err != nil { - return err - } - err = reportRepos(cmd, repoNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") + // Repository + fmt.Fprintln(cmd.OutOrStdout(), "repos:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + repoNames, err := Client.ListRepoNames() + if err != nil { + return err + } + err = reportRepos(cmd, repoNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") - // Image - fmt.Fprintln(cmd.OutOrStdout(), "images:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - imageNames, err := Client.ListImageNames() - if err != nil { - return err - } - err = reportImages(cmd, imageNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") + // Image + fmt.Fprintln(cmd.OutOrStdout(), "images:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + imageNames, err := Client.ListImageNames() + if err != nil { + return err + } + err = reportImages(cmd, imageNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") - // Mgmtclass - fmt.Fprintln(cmd.OutOrStdout(), "mgmtclasses:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - mgmtClassNames, err := Client.ListMgmtClassNames() - if err != nil { - return err - } - err = reportMgmtClasses(cmd, mgmtClassNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") + // Mgmtclass + fmt.Fprintln(cmd.OutOrStdout(), "mgmtclasses:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + mgmtClassNames, err := Client.ListMgmtClassNames() + if err != nil { + return err + } + err = reportMgmtClasses(cmd, mgmtClassNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") - // Package - fmt.Fprintln(cmd.OutOrStdout(), "packages:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - packageNames, err := Client.ListPackageNames() - if err != nil { - return err - } - err = reportPackages(cmd, packageNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") + // Package + fmt.Fprintln(cmd.OutOrStdout(), "packages:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + packageNames, err := Client.ListPackageNames() + if err != nil { + return err + } + err = reportPackages(cmd, packageNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") - // File - fmt.Fprintln(cmd.OutOrStdout(), "files:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - fileNames, err := Client.ListFileNames() - if err != nil { - return err - } - err = reportFiles(cmd, fileNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") + // File + fmt.Fprintln(cmd.OutOrStdout(), "files:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + fileNames, err := Client.ListFileNames() + if err != nil { + return err + } + err = reportFiles(cmd, fileNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") - // Menu - fmt.Fprintln(cmd.OutOrStdout(), "menus:") - fmt.Fprintln(cmd.OutOrStdout(), "==========") - menuNames, err := Client.ListMenuNames() - if err != nil { - return err - } - err = reportMenus(cmd, menuNames) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), "") - return nil - }, -} - -func init() { - rootCmd.AddCommand(reportCmd) + // Menu + fmt.Fprintln(cmd.OutOrStdout(), "menus:") + fmt.Fprintln(cmd.OutOrStdout(), "==========") + menuNames, err := Client.ListMenuNames() + if err != nil { + return err + } + err = reportMenus(cmd, menuNames) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), "") + return nil + }, + } + return reportCmd } diff --git a/cmd/reposync.go b/cmd/reposync.go index ca7e812..a67b6c1 100644 --- a/cmd/reposync.go +++ b/cmd/reposync.go @@ -10,52 +10,49 @@ import ( "github.com/spf13/cobra" ) -// reposyncCmd represents the reposync command -var reposyncCmd = &cobra.Command{ - Use: "reposync", - Short: "Sync repositories", - Long: `Update and sync Cobbler repositories. The repositories have to be added beforehand via 'cobbler repo add'. +// NewRepoSyncCmd builds a new command that represents the reposync action +func NewRepoSyncCmd() *cobra.Command { + reposyncCmd := &cobra.Command{ + Use: "reposync", + Short: "Sync repositories", + Long: `Update and sync Cobbler repositories. The repositories have to be added beforehand via 'cobbler repo add'. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-reposync for more information.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - noFailOption, err := cmd.Flags().GetBool("no-fail") - if err != nil { - return err - } - onlyOption, err := cmd.Flags().GetString("only") - if err != nil { - return err - } - triesOption, err := cmd.Flags().GetInt("tries") - if err != nil { - return err - } - var reposyncOptions = cobblerclient.BackgroundReposyncOptions{ - Repos: make([]string, 0), - Only: onlyOption, - Nofail: noFailOption, - Tries: triesOption, - } - eventId, err := Client.BackgroundReposync(reposyncOptions) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) - return nil - }, -} - -func init() { - rootCmd.AddCommand(reposyncCmd) - - //local flags + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + noFailOption, err := cmd.Flags().GetBool("no-fail") + if err != nil { + return err + } + onlyOption, err := cmd.Flags().GetString("only") + if err != nil { + return err + } + triesOption, err := cmd.Flags().GetInt("tries") + if err != nil { + return err + } + var reposyncOptions = cobblerclient.BackgroundReposyncOptions{ + Repos: make([]string, 0), + Only: onlyOption, + Nofail: noFailOption, + Tries: triesOption, + } + eventId, err := Client.BackgroundReposync(reposyncOptions) + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil + }, + } reposyncCmd.Flags().Bool("no-fail", false, "do not stop reposyncing if a failure occurs") reposyncCmd.Flags().String("only", "", "update only this repository name") reposyncCmd.Flags().Int("tries", 3, "try each repo this many times") + return reposyncCmd } diff --git a/cmd/root.go b/cmd/root.go index 81beda7..71d41ac 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -24,30 +24,62 @@ var conf cobbler.ClientConfig var httpClient = &http.Client{} var verbose bool -// rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ - Use: "cobbler", - Short: "Cobbler CLI client", - Long: "An independent CLI to manage a Cobbler server.", - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, +// NewRootCmd builds a new command that represents the base action when called without any subcommands +func NewRootCmd() *cobra.Command { + rootCmd := &cobra.Command{ + Use: "cobbler", + Short: "Cobbler CLI client", + Long: "An independent CLI to manage a Cobbler server.", + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + + // global flags + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobbler.yaml)") + rootCmd.Flags().BoolVar(&verbose, "verbose", false, "Whether or not to print debug messages from the CLI.") + + // Add sub commands + rootCmd.AddCommand(NewAclSetupCmd()) + rootCmd.AddCommand(NewBuildisoCmd()) + distroCmd, err := NewDistroCmd() + cobra.CheckErr(err) + rootCmd.AddCommand(distroCmd) + rootCmd.AddCommand(NewEventCmd()) + rootCmd.AddCommand(NewFileCmd()) + rootCmd.AddCommand(NewHardlinkCmd()) + rootCmd.AddCommand(NewImageCmd()) + rootCmd.AddCommand(NewImportCmd()) + rootCmd.AddCommand(NewListCmd()) + rootCmd.AddCommand(NewMenuCmd()) + rootCmd.AddCommand(NewMgmtClassCmd()) + rootCmd.AddCommand(NewMkLoadersCmd()) + rootCmd.AddCommand(NewPackageCmd()) + rootCmd.AddCommand(NewProfileCmd()) + rootCmd.AddCommand(NewReplicateCmd()) + rootCmd.AddCommand(NewRepoCmd()) + rootCmd.AddCommand(NewReportCmd()) + rootCmd.AddCommand(NewRepoSyncCmd()) + rootCmd.AddCommand(NewSettingCmd()) + rootCmd.AddCommand(NewSignatureCmd()) + rootCmd.AddCommand(NewSyncCmd()) + rootCmd.AddCommand(NewSystemCmd()) + rootCmd.AddCommand(NewValidateAutoinstallsCmd()) + rootCmd.AddCommand(NewVersionCmd()) + return rootCmd } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + + // Execute root command cobra.CheckErr(rootCmd.Execute()) } -func init() { - cobra.OnInitialize(initConfig) - - // global flags - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobbler.yaml)") - rootCmd.Flags().BoolVar(&verbose, "verbose", false, "Whether or not to print debug messages from the CLI.") - - // Setup logger +func setupLogger() { if !verbose { slog.SetLogLoggerLevel(slog.LevelWarn) } diff --git a/cmd/setting.go b/cmd/setting.go index 95cef69..73cee0d 100644 --- a/cmd/setting.go +++ b/cmd/setting.go @@ -10,85 +10,86 @@ import ( "os" ) -// settingCmd represents the setting command -var settingCmd = &cobra.Command{ - Use: "setting", - Short: "Settings management", - Long: `Let you manage settings.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, +// NewSettingCmd builds a new command that represents the setting action +func NewSettingCmd() *cobra.Command { + settingCmd := &cobra.Command{ + Use: "setting", + Short: "Settings management", + Long: `Let you manage settings.`, + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + settingCmd.AddCommand(NewSettingEditCmd()) + settingCmd.AddCommand(NewSettingReportCmd()) + return settingCmd } -var settingEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit settings", - Long: `Edits the settings.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewSettingEditCmd() *cobra.Command { + settingEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit settings", + Long: `Edits the settings.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - settings, err := Client.GetSettings() - if err != nil { - return err - } - if !settings.AllowDynamicSettings { - fmt.Fprintln(cmd.OutOrStdout(), "Dynamic settings are turned off server-side!") - os.Exit(1) - } + settings, err := Client.GetSettings() + if err != nil { + return err + } + if !settings.AllowDynamicSettings { + fmt.Fprintln(cmd.OutOrStdout(), "Dynamic settings are turned off server-side!") + os.Exit(1) + } - settingName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - settingValue, err := cmd.Flags().GetString("value") - if err != nil { - return err - } - result, err := Client.ModifySetting(settingName, settingValue) - if err != nil { - return err - } - if result == 0 { - fmt.Fprintln(cmd.OutOrStdout(), "Successfully updated!") - } else { - fmt.Fprintln(cmd.OutOrStdout(), "Updating settings failed!") - } - return nil - }, -} - -var settingReportCmd = &cobra.Command{ - Use: "report", - Short: "list settings", - Long: `Prints settings to stdout.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - settings, err := Client.GetSettings() - if err != nil { - return err - } - - printStructured(cmd, settings) - return nil - }, + settingName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + settingValue, err := cmd.Flags().GetString("value") + if err != nil { + return err + } + result, err := Client.ModifySetting(settingName, settingValue) + if err != nil { + return err + } + if result == 0 { + fmt.Fprintln(cmd.OutOrStdout(), "Successfully updated!") + } else { + fmt.Fprintln(cmd.OutOrStdout(), "Updating settings failed!") + } + return nil + }, + } + settingEditCmd.Flags().String("name", "", "the settings name to edit (e.g. server)") + settingEditCmd.Flags().String("value", "", "the new value (e.g. 127.0.0.1)") + return settingEditCmd } -func init() { - rootCmd.AddCommand(settingCmd) - settingCmd.AddCommand(settingEditCmd) - settingCmd.AddCommand(settingReportCmd) +func NewSettingReportCmd() *cobra.Command { + settingReportCmd := &cobra.Command{ + Use: "report", + Short: "list settings", + Long: `Prints settings to stdout.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for setting edit - settingEditCmd.Flags().String("name", "", "the settings name to edit (e.g. server)") - settingEditCmd.Flags().String("value", "", "the new value (e.g. 127.0.0.1)") + settings, err := Client.GetSettings() + if err != nil { + return err + } - // local flags for setting report + printStructured(cmd, settings) + return nil + }, + } settingReportCmd.Flags().String("name", "", "the settings name to show") + return settingReportCmd } diff --git a/cmd/signature.go b/cmd/signature.go index f90a298..49fadc6 100644 --- a/cmd/signature.go +++ b/cmd/signature.go @@ -10,103 +10,111 @@ import ( "sort" ) -// signatureCmd represents the signature command -var signatureCmd = &cobra.Command{ - Use: "signature", - Short: "Signature management", - Long: `Reloads, reports or updates the signatures of the distinct operating system versions.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintln(cmd.OutOrStdout(), "Please use one of the sub commands!") - _ = cmd.Help() - }, +// NewSignatureCmd builds a new command that represents the signature action +func NewSignatureCmd() *cobra.Command { + signatureCmd := &cobra.Command{ + Use: "signature", + Short: "Signature management", + Long: `Reloads, reports or updates the signatures of the distinct operating system versions.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Fprintln(cmd.OutOrStdout(), "Please use one of the sub commands!") + _ = cmd.Help() + }, + } + signatureCmd.AddCommand(NewSignatureReloadCmd()) + signatureCmd.AddCommand(NewSignatureReportCmd()) + signatureCmd.AddCommand(NewSignatureUpdateCmd()) + return signatureCmd } -var signatureReportCmd = &cobra.Command{ - Use: "report", - Short: "Report the loaded signatures", - Long: `Report the loaded signatures`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewSignatureReportCmd() *cobra.Command { + signatureReportCmd := &cobra.Command{ + Use: "report", + Short: "Report the loaded signatures", + Long: `Report the loaded signatures`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // Get signatures - signatures, err := Client.GetSignatures() - if err != nil { - return err - } + // Get signatures + signatures, err := Client.GetSignatures() + if err != nil { + return err + } - if len(signatures.Breeds) > 0 { - // Counters - var totalOsVersions int + if len(signatures.Breeds) > 0 { + // Counters + var totalOsVersions int - // Print signatures - fmt.Fprintln(cmd.OutOrStdout(), "Currently loaded signatures") - breedNameList := make([]string, 0, len(signatures.Breeds)) - for key := range signatures.Breeds { - breedNameList = append(breedNameList, key) - } - sort.Strings(breedNameList) - for _, breedName := range breedNameList { - fmt.Fprintln(cmd.OutOrStdout(), breedName) - totalOsVersions += len(signatures.Breeds[breedName]) - if len(signatures.Breeds[breedName]) > 0 { - osVersionNameList := make([]string, 0, len(signatures.Breeds[breedName])) - for key := range signatures.Breeds[breedName] { - osVersionNameList = append(osVersionNameList, key) - } - sort.Strings(osVersionNameList) - for _, versionName := range osVersionNameList { - fmt.Fprintf(cmd.OutOrStdout(), "\t%s\n", versionName) - } - } else { - fmt.Fprintln(cmd.OutOrStdout(), "\t(none)") + // Print signatures + fmt.Fprintln(cmd.OutOrStdout(), "Currently loaded signatures") + breedNameList := make([]string, 0, len(signatures.Breeds)) + for key := range signatures.Breeds { + breedNameList = append(breedNameList, key) } + sort.Strings(breedNameList) + for _, breedName := range breedNameList { + fmt.Fprintln(cmd.OutOrStdout(), breedName) + totalOsVersions += len(signatures.Breeds[breedName]) + if len(signatures.Breeds[breedName]) > 0 { + osVersionNameList := make([]string, 0, len(signatures.Breeds[breedName])) + for key := range signatures.Breeds[breedName] { + osVersionNameList = append(osVersionNameList, key) + } + sort.Strings(osVersionNameList) + for _, versionName := range osVersionNameList { + fmt.Fprintf(cmd.OutOrStdout(), "\t%s\n", versionName) + } + } else { + fmt.Fprintln(cmd.OutOrStdout(), "\t(none)") + } + } + fmt.Fprintf(cmd.OutOrStdout(), "\n%d breeds with %d total OS versions loaded\n", len(signatures.Breeds), totalOsVersions) + } else { + fmt.Fprintln(cmd.OutOrStdout(), "No breeds found in the signature, a signature update is recommended") } - fmt.Fprintf(cmd.OutOrStdout(), "\n%d breeds with %d total OS versions loaded\n", len(signatures.Breeds), totalOsVersions) - } else { - fmt.Fprintln(cmd.OutOrStdout(), "No breeds found in the signature, a signature update is recommended") - } - return nil - }, + return nil + }, + } + return signatureReportCmd } -var signatureUpdateCmd = &cobra.Command{ - Use: "update", - Short: "Update the signatures JSON file", - Long: `Retrieve an up-to-date "distro_signatures.json" file from the server-side configured webservice.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +func NewSignatureUpdateCmd() *cobra.Command { + signatureUpdateCmd := &cobra.Command{ + Use: "update", + Short: "Update the signatures JSON file", + Long: `Retrieve an up-to-date "distro_signatures.json" file from the server-side configured webservice.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - eventId, _ := Client.BackgroundSignatureUpdate() - fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) - return nil - }, + eventId, _ := Client.BackgroundSignatureUpdate() + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil + }, + } + return signatureUpdateCmd } -var signatureReloadCmd = &cobra.Command{ - Use: "reload", - Short: "Reloads signatures", - Long: `Reloads signatures from the - on the server - local "distro_signatures.json" file.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - fmt.Fprintln(cmd.OutOrStdout(), "This functionality cannot be used in the new CLI until https://github.com/cobbler/cobbler/issues/3791 is implemented!") - return nil - }, -} +func NewSignatureReloadCmd() *cobra.Command { + signatureReloadCmd := &cobra.Command{ + Use: "reload", + Short: "Reloads signatures", + Long: `Reloads signatures from the - on the server - local "distro_signatures.json" file.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } -func init() { - signatureCmd.AddCommand(signatureReloadCmd) - signatureCmd.AddCommand(signatureReportCmd) - signatureCmd.AddCommand(signatureUpdateCmd) - rootCmd.AddCommand(signatureCmd) + fmt.Fprintln(cmd.OutOrStdout(), "This functionality cannot be used in the new CLI until https://github.com/cobbler/cobbler/issues/3791 is implemented!") + return nil + }, + } + return signatureReloadCmd } diff --git a/cmd/sync.go b/cmd/sync.go index aa745d9..65a45b6 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -10,70 +10,67 @@ import ( "github.com/spf13/cobra" ) -// syncCmd represents the sync command -var syncCmd = &cobra.Command{ - Use: "sync", - Short: "Sync Cobbler", - Long: `Force a rewrite of all configuration files, distribution files in the TFTP root, and restart managed +// NewSyncCmd builds a command that represents the sync action +func NewSyncCmd() *cobra.Command { + syncCmd := &cobra.Command{ + Use: "sync", + Short: "Sync Cobbler", + Long: `Force a rewrite of all configuration files, distribution files in the TFTP root, and restart managed services. It is used to repair or rebuild the contents of '/tftpboot' or '/var/www/cobbler' or when something has changed behind the scenes. It brings the filesystem up to date with the configuration. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-sync for more information.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - dhcpOption, err := cmd.Flags().GetBool("dhcp") - if err != nil { - return err - } - dnsOption, err := cmd.Flags().GetBool("dns") - if err != nil { - return err - } - verboseOption, err := cmd.Flags().GetBool("verbose") - if err != nil { - return err - } - systemsOption, err := cmd.Flags().GetStringSlice("systems") - if err != nil { - return err - } + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - var eventId string - if len(systemsOption) > 0 { - backgroundSyncSystemsOptions := cobblerclient.BackgroundSyncSystemsOptions{ - Systems: systemsOption, - Verbose: verboseOption, + dhcpOption, err := cmd.Flags().GetBool("dhcp") + if err != nil { + return err } - eventId, err = Client.BackgroundSyncSystems(backgroundSyncSystemsOptions) - } else { - backgroundSyncOptions := cobblerclient.BackgroundSyncOptions{ - Dhcp: dhcpOption, - Dns: dnsOption, - Verbose: verboseOption, + dnsOption, err := cmd.Flags().GetBool("dns") + if err != nil { + return err + } + verboseOption, err := cmd.Flags().GetBool("verbose") + if err != nil { + return err + } + systemsOption, err := cmd.Flags().GetStringSlice("systems") + if err != nil { + return err } - eventId, err = Client.BackgroundSync(backgroundSyncOptions) - } - - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) - return nil - }, -} -func init() { - rootCmd.AddCommand(syncCmd) + var eventId string + if len(systemsOption) > 0 { + backgroundSyncSystemsOptions := cobblerclient.BackgroundSyncSystemsOptions{ + Systems: systemsOption, + Verbose: verboseOption, + } + eventId, err = Client.BackgroundSyncSystems(backgroundSyncSystemsOptions) + } else { + backgroundSyncOptions := cobblerclient.BackgroundSyncOptions{ + Dhcp: dhcpOption, + Dns: dnsOption, + Verbose: verboseOption, + } + eventId, err = Client.BackgroundSync(backgroundSyncOptions) + } - //local flags + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil + }, + } syncCmd.Flags().Bool("dhcp", false, "write DHCP config files and restart service") syncCmd.Flags().Bool("dns", false, "write DNS config files and restart service") syncCmd.Flags().StringSlice("systems", []string{}, "run a sync only on specified systems") syncCmd.Flags().Bool("verbose", false, "more verbose output") syncCmd.MarkFlagsMutuallyExclusive("dhcp", "systems") syncCmd.MarkFlagsMutuallyExclusive("dns", "systems") + return syncCmd } diff --git a/cmd/system.go b/cmd/system.go index 9a238de..99d5d95 100644 --- a/cmd/system.go +++ b/cmd/system.go @@ -763,457 +763,66 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { return err } -// systemCmd represents the system command -var systemCmd = &cobra.Command{ - Use: "system", - Short: "System management", - Long: `Let you manage systems. +// NewSystemCmd builds a new command that represents the system action +func NewSystemCmd() *cobra.Command { + systemCmd := &cobra.Command{ + Use: "system", + Short: "System management", + Long: `Let you manage systems. See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-system for more information.`, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd.Help() - }, -} - -var systemAddCmd = &cobra.Command{ - Use: "add", - Short: "add system", - Long: `Adds a system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - newSystem := cobbler.NewSystem() - - // internal fields (ctime, mtime, depth, uid, repos-enabled, ipv6-autoconfiguration) cannot be modified - newSystem.Name, err = cmd.Flags().GetString("name") - if err != nil { - return err - } - // Update system in-memory - err = updateSystemFromFlags(cmd, &newSystem) - if err != nil { - return err - } - // No create the system via XML-RPC - system, err := Client.CreateSystem(newSystem) - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "System %s created\n", system.Name) - return nil - }, + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + systemCmd.AddCommand(NewSystemAddCmd()) + systemCmd.AddCommand(NewSystemCopyCmd()) + systemCmd.AddCommand(NewSystemDumpVarsCmd()) + systemCmd.AddCommand(NewSystemEditCmd()) + systemCmd.AddCommand(NewSystemFindCmd()) + systemCmd.AddCommand(NewSystemGetAutoinstallCmd()) + systemCmd.AddCommand(NewSystemListCmd()) + systemCmd.AddCommand(NewSystemPowerOffCmd()) + systemCmd.AddCommand(NewSystemPowerOnCmd()) + systemCmd.AddCommand(NewSystemPowerStatusCmd()) + systemCmd.AddCommand(NewSystemRebootCmd()) + systemCmd.AddCommand(NewSystemRemoveCmd()) + systemCmd.AddCommand(NewSystemRenameCmd()) + systemCmd.AddCommand(NewSystemReportCmd()) + return systemCmd } -var systemCopyCmd = &cobra.Command{ - Use: "copy", - Short: "copy system", - Long: `Copies a system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - systemNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - systemHandle, err := Client.GetSystemHandle(systemName) - if err != nil { - return err - } - err = Client.CopySystem(systemHandle, systemNewName) - if err != nil { - return err - } - newSystem, err := Client.GetSystem(systemNewName, false, false) - if err != nil { - return err - } - // Update the system in-memory - err = updateSystemFromFlags(cmd, newSystem) - if err != nil { - return err - } - if newSystem.Meta.IsDirty { - newSystem, err = Client.GetSystem( - newSystem.Name, - newSystem.Meta.IsFlattened, - newSystem.Meta.IsResolved, - ) +func NewSystemAddCmd() *cobra.Command { + systemAddCmd := &cobra.Command{ + Use: "add", + Short: "add system", + Long: `Adds a system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() if err != nil { return err } - } - // Update the system via XML-RPC - return Client.UpdateSystem(newSystem) - }, -} - -var systemDumpVarsCmd = &cobra.Command{ - Use: "dumpvars", - Short: "dump system variables", - Long: `Prints all system variables to stdout.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get CLI flags - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - - // Now retrieve data - blendedData, err := Client.GetBlendedData("", systemName) - if err != nil { - return err - } - // Print data - printDumpVars(cmd, blendedData) - return err - }, -} - -var systemEditCmd = &cobra.Command{ - Use: "edit", - Short: "edit system", - Long: `Edits a system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - // find profile through its name - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - updateSystem, err := Client.GetSystem(systemName, false, false) - if err != nil { - return err - } + newSystem := cobbler.NewSystem() - // Update the system in-memory - err = updateSystemFromFlags(cmd, updateSystem) - if err != nil { - return err - } - if updateSystem.Meta.IsDirty { - updateSystem, err = Client.GetSystem( - updateSystem.Name, - updateSystem.Meta.IsFlattened, - updateSystem.Meta.IsResolved, - ) + // internal fields (ctime, mtime, depth, uid, repos-enabled, ipv6-autoconfiguration) cannot be modified + newSystem.Name, err = cmd.Flags().GetString("name") if err != nil { return err } - } - // Update the system via XML-RPC - return Client.UpdateSystem(updateSystem) - }, -} - -var systemFindCmd = &cobra.Command{ - Use: "find", - Short: "find system", - Long: `Finds a given system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return FindItemNames(cmd, args, "system") - }, -} - -var systemGetAutoinstallCmd = &cobra.Command{ - Use: "get-autoinstall", - Short: "dump autoinstall XML", - Long: `Prints the autoinstall XML file of the given system to stdout.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - systemExists, err := Client.HasItem("system", systemName) - if err != nil { - return err - } - if !systemExists { - //goland:noinspection GoErrorStringFormat - return fmt.Errorf("System does not exist") - } - autoinstallRendered, err := Client.GenerateAutoinstall("", systemName) - if err != nil { - return err - } - fmt.Fprintln(cmd.OutOrStdout(), autoinstallRendered) - return nil - }, -} - -var systemListCmd = &cobra.Command{ - Use: "list", - Short: "list all systems", - Long: `Lists all available systems.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - systemNames, err := Client.ListSystemNames() - if err != nil { - return err - } - listItems(cmd, "systems", systemNames) - return nil - }, -} - -var systemPowerOffCmd = &cobra.Command{ - Use: "poweroff", - Short: "power off system", - Long: `Powers off the selected system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get flags - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - - // Perform action - systemHandle, err := Client.GetSystemHandle(systemName) - if err != nil { - return err - } - _, err = Client.PowerSystem(systemHandle, "off") - return err - }, -} - -var systemPowerOnCmd = &cobra.Command{ - Use: "poweron", - Short: "power on system", - Long: `Powers on the selected system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get flags - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - - // Perform action - systemHandle, err := Client.GetSystemHandle(systemName) - if err != nil { - return err - } - _, err = Client.PowerSystem(systemHandle, "on") - return err - }, -} - -var systemPowerStatusCmd = &cobra.Command{ - Use: "powerstatus", - Short: "Power status of the system", - Long: `Querys the power status of the selected system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get flags - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - - // Perform action - systemHandle, err := Client.GetSystemHandle(systemName) - if err != nil { - return err - } - _, err = Client.PowerSystem(systemHandle, "status") - return err - }, -} - -var systemRebootCmd = &cobra.Command{ - Use: "reboot", - Short: "reboot system", - Long: `Reboots the selected system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get flags - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - - // Perform action - systemHandle, err := Client.GetSystemHandle(systemName) - if err != nil { - return err - } - _, err = Client.PowerSystem(systemHandle, "reboot") - return err - }, -} - -var systemRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "remove system", - Long: `Removes a given system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - return RemoveItemRecursive(cmd, args, "system") - }, -} - -var systemRenameCmd = &cobra.Command{ - Use: "rename", - Short: "rename system", - Long: `Renames a given system.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - // Get flags - systemName, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - systemNewName, err := cmd.Flags().GetString("newname") - if err != nil { - return err - } - - // Perform action - systemHandle, err := Client.GetSystemHandle(systemName) - if err != nil { - return err - } - err = Client.RenameSystem(systemHandle, systemNewName) - if err != nil { - return err - } - newSystem, err := Client.GetSystem(systemNewName, false, false) - if err != nil { - return err - } - err = updateSystemFromFlags(cmd, newSystem) - if err != nil { - return err - } - if newSystem.Meta.IsDirty { - newSystem, err = Client.GetSystem( - newSystem.Name, - newSystem.Meta.IsFlattened, - newSystem.Meta.IsResolved, - ) + // Update system in-memory + err = updateSystemFromFlags(cmd, &newSystem) if err != nil { return err } - } - return Client.UpdateSystem(newSystem) - }, -} - -func reportSystems(cmd *cobra.Command, systemNames []string) error { - for _, itemName := range systemNames { - system, err := Client.GetSystem(itemName, false, false) - if err != nil { - return err - } - printStructured(cmd, system) - fmt.Fprintln(cmd.OutOrStdout(), "") - } - return nil -} - -var systemReportCmd = &cobra.Command{ - Use: "report", - Short: "list all systems in detail", - Long: `Shows detailed information about all systems.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - - name, err := cmd.Flags().GetString("name") - if err != nil { - return err - } - itemNames := make([]string, 0) - if name == "" { - itemNames, err = Client.ListSystemNames() + // Now create the system via XML-RPC + system, err := Client.CreateSystem(newSystem) if err != nil { return err } - } else { - itemNames = append(itemNames, name) - } - return reportSystems(cmd, itemNames) - }, -} - -func init() { - rootCmd.AddCommand(systemCmd) - systemCmd.AddCommand(systemAddCmd) - systemCmd.AddCommand(systemCopyCmd) - systemCmd.AddCommand(systemDumpVarsCmd) - systemCmd.AddCommand(systemEditCmd) - systemCmd.AddCommand(systemFindCmd) - systemCmd.AddCommand(systemGetAutoinstallCmd) - systemCmd.AddCommand(systemListCmd) - systemCmd.AddCommand(systemPowerOffCmd) - systemCmd.AddCommand(systemPowerOnCmd) - systemCmd.AddCommand(systemPowerStatusCmd) - systemCmd.AddCommand(systemRebootCmd) - systemCmd.AddCommand(systemRemoveCmd) - systemCmd.AddCommand(systemRenameCmd) - systemCmd.AddCommand(systemReportCmd) - - // local flags for system add + fmt.Fprintf(cmd.OutOrStdout(), "System %s created\n", system.Name) + return nil + }, + } addCommonArgs(systemAddCmd) addStringFlags(systemAddCmd, systemStringFlagMetadata) addStringFlags(systemAddCmd, systemPowerStringFlagMetadata) @@ -1229,8 +838,60 @@ func init() { // Other systemAddCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") systemAddCmd.Flags().String("interface", "", "the interface to operate on") + return systemAddCmd +} + +func NewSystemCopyCmd() *cobra.Command { + systemCopyCmd := &cobra.Command{ + Use: "copy", + Short: "copy system", + Long: `Copies a system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for system copy + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + systemNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } + + systemHandle, err := Client.GetSystemHandle(systemName) + if err != nil { + return err + } + err = Client.CopySystem(systemHandle, systemNewName) + if err != nil { + return err + } + newSystem, err := Client.GetSystem(systemNewName, false, false) + if err != nil { + return err + } + // Update the system in-memory + err = updateSystemFromFlags(cmd, newSystem) + if err != nil { + return err + } + if newSystem.Meta.IsDirty { + newSystem, err = Client.GetSystem( + newSystem.Name, + newSystem.Meta.IsFlattened, + newSystem.Meta.IsResolved, + ) + if err != nil { + return err + } + } + // Update the system via XML-RPC + return Client.UpdateSystem(newSystem) + }, + } addCommonArgs(systemCopyCmd) addStringFlags(systemCopyCmd, systemStringFlagMetadata) addStringFlags(systemCopyCmd, systemPowerStringFlagMetadata) @@ -1248,11 +909,80 @@ func init() { systemCopyCmd.Flags().String("interface", "", "the interface to operate on") systemCopyCmd.Flags().Bool("delete-interface", false, "delete the given interface (should be used with --interface)") systemCopyCmd.Flags().String("rename-interface", "", "rename the given interface (should be used with --interface)") + return systemCopyCmd +} + +func NewSystemDumpVarsCmd() *cobra.Command { + systemDumpVarsCmd := &cobra.Command{ + Use: "dumpvars", + Short: "dump system variables", + Long: `Prints all system variables to stdout.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // Get CLI flags + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } - // local flags for system dumpvars + // Now retrieve data + blendedData, err := Client.GetBlendedData("", systemName) + if err != nil { + return err + } + // Print data + printDumpVars(cmd, blendedData) + return err + }, + } systemDumpVarsCmd.Flags().String("name", "", "the system name") + return systemDumpVarsCmd +} + +func NewSystemEditCmd() *cobra.Command { + systemEditCmd := &cobra.Command{ + Use: "edit", + Short: "edit system", + Long: `Edits a system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // find profile through its name + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + updateSystem, err := Client.GetSystem(systemName, false, false) + if err != nil { + return err + } - // local flags for system edit + // Update the system in-memory + err = updateSystemFromFlags(cmd, updateSystem) + if err != nil { + return err + } + if updateSystem.Meta.IsDirty { + updateSystem, err = Client.GetSystem( + updateSystem.Name, + updateSystem.Meta.IsFlattened, + updateSystem.Meta.IsResolved, + ) + if err != nil { + return err + } + } + // Update the system via XML-RPC + return Client.UpdateSystem(updateSystem) + }, + } addCommonArgs(systemEditCmd) addStringFlags(systemEditCmd, systemStringFlagMetadata) addStringFlags(systemEditCmd, systemPowerStringFlagMetadata) @@ -1270,8 +1000,23 @@ func init() { systemEditCmd.Flags().String("interface", "", "the interface to operate on") systemEditCmd.Flags().Bool("delete-interface", false, "delete the given interface (should be used with --interface)") systemEditCmd.Flags().String("rename-interface", "", "rename the given interface (should be used with --interface)") + return systemEditCmd +} - // local flags for system find +func NewSystemFindCmd() *cobra.Command { + systemFindCmd := &cobra.Command{ + Use: "find", + Short: "find system", + Long: `Finds a given system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + return FindItemNames(cmd, args, "system") + }, + } addCommonArgs(systemFindCmd) addStringFlags(systemFindCmd, systemStringFlagMetadata) addStringFlags(systemFindCmd, systemPowerStringFlagMetadata) @@ -1289,27 +1034,256 @@ func init() { addIntFlags(systemFindCmd, findIntFlagMetadata) addFloatFlags(systemFindCmd, findFloatFlagMetadata) systemFindCmd.Flags().String("interface", "", "the interface to operate on") + return systemFindCmd +} - // local flags for system get-autoinstall +func NewSystemGetAutoinstallCmd() *cobra.Command { + systemGetAutoinstallCmd := &cobra.Command{ + Use: "get-autoinstall", + Short: "dump autoinstall XML", + Long: `Prints the autoinstall XML file of the given system to stdout.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + systemExists, err := Client.HasItem("system", systemName) + if err != nil { + return err + } + if !systemExists { + //goland:noinspection GoErrorStringFormat + return fmt.Errorf("System does not exist") + } + autoinstallRendered, err := Client.GenerateAutoinstall("", systemName) + if err != nil { + return err + } + fmt.Fprintln(cmd.OutOrStdout(), autoinstallRendered) + return nil + }, + } systemGetAutoinstallCmd.Flags().String("name", "", "the system name") + return systemGetAutoinstallCmd +} + +func NewSystemListCmd() *cobra.Command { + systemListCmd := &cobra.Command{ + Use: "list", + Short: "list all systems", + Long: `Lists all available systems.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + systemNames, err := Client.ListSystemNames() + if err != nil { + return err + } + listItems(cmd, "systems", systemNames) + return nil + }, + } + return systemListCmd +} - // local flags for system poweroff +func NewSystemPowerOffCmd() *cobra.Command { + systemPowerOffCmd := &cobra.Command{ + Use: "poweroff", + Short: "power off system", + Long: `Powers off the selected system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // Get flags + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + + // Perform action + systemHandle, err := Client.GetSystemHandle(systemName) + if err != nil { + return err + } + _, err = Client.PowerSystem(systemHandle, "off") + return err + }, + } systemPowerOffCmd.Flags().String("name", "", "the system name") + return systemPowerOffCmd +} + +func NewSystemPowerOnCmd() *cobra.Command { + systemPowerOnCmd := &cobra.Command{ + Use: "poweron", + Short: "power on system", + Long: `Powers on the selected system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - // local flags for system poweron + // Get flags + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + + // Perform action + systemHandle, err := Client.GetSystemHandle(systemName) + if err != nil { + return err + } + _, err = Client.PowerSystem(systemHandle, "on") + return err + }, + } systemPowerOnCmd.Flags().String("name", "", "the system name") + return systemPowerOnCmd +} + +func NewSystemPowerStatusCmd() *cobra.Command { + systemPowerStatusCmd := &cobra.Command{ + Use: "powerstatus", + Short: "Power status of the system", + Long: `Querys the power status of the selected system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // Get flags + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } - // local flags for system powerstatus + // Perform action + systemHandle, err := Client.GetSystemHandle(systemName) + if err != nil { + return err + } + _, err = Client.PowerSystem(systemHandle, "status") + return err + }, + } systemPowerStatusCmd.Flags().String("name", "", "the system name") + return systemPowerStatusCmd +} + +func NewSystemRebootCmd() *cobra.Command { + systemRebootCmd := &cobra.Command{ + Use: "reboot", + Short: "reboot system", + Long: `Reboots the selected system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // Get flags + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } - // local flags for system reboot + // Perform action + systemHandle, err := Client.GetSystemHandle(systemName) + if err != nil { + return err + } + _, err = Client.PowerSystem(systemHandle, "reboot") + return err + }, + } systemRebootCmd.Flags().String("name", "", "the system name") + return systemRebootCmd +} - // local flags for system remove +func NewSystemRemoveCmd() *cobra.Command { + systemRemoveCmd := &cobra.Command{ + Use: "remove", + Short: "remove system", + Long: `Removes a given system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + return RemoveItemRecursive(cmd, args, "system") + }, + } systemRemoveCmd.Flags().String("name", "", "the system name") systemRemoveCmd.Flags().Bool("recursive", false, "also delete child objects") + return systemRemoveCmd +} - // local flags for system rename +func NewSystemRenameCmd() *cobra.Command { + systemRenameCmd := &cobra.Command{ + Use: "rename", + Short: "rename system", + Long: `Renames a given system.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + // Get flags + systemName, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + systemNewName, err := cmd.Flags().GetString("newname") + if err != nil { + return err + } + + // Perform action + systemHandle, err := Client.GetSystemHandle(systemName) + if err != nil { + return err + } + err = Client.RenameSystem(systemHandle, systemNewName) + if err != nil { + return err + } + newSystem, err := Client.GetSystem(systemNewName, false, false) + if err != nil { + return err + } + err = updateSystemFromFlags(cmd, newSystem) + if err != nil { + return err + } + if newSystem.Meta.IsDirty { + newSystem, err = Client.GetSystem( + newSystem.Name, + newSystem.Meta.IsFlattened, + newSystem.Meta.IsResolved, + ) + if err != nil { + return err + } + } + return Client.UpdateSystem(newSystem) + }, + } addCommonArgs(systemRenameCmd) addStringFlags(systemRenameCmd, systemStringFlagMetadata) addStringFlags(systemRenameCmd, systemPowerStringFlagMetadata) @@ -1328,7 +1302,48 @@ func init() { systemRenameCmd.Flags().String("interface", "", "the interface to operate on") systemRenameCmd.Flags().Bool("delete-interface", false, "delete the given interface (should be used with --interface)") systemRenameCmd.Flags().String("rename-interface", "", "rename the given interface (should be used with --interface)") + return systemRenameCmd +} + +func reportSystems(cmd *cobra.Command, systemNames []string) error { + for _, itemName := range systemNames { + system, err := Client.GetSystem(itemName, false, false) + if err != nil { + return err + } + printStructured(cmd, system) + fmt.Fprintln(cmd.OutOrStdout(), "") + } + return nil +} - // local flags for system report +func NewSystemReportCmd() *cobra.Command { + systemReportCmd := &cobra.Command{ + Use: "report", + Short: "list all systems in detail", + Long: `Shows detailed information about all systems.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + itemNames := make([]string, 0) + if name == "" { + itemNames, err = Client.ListSystemNames() + if err != nil { + return err + } + } else { + itemNames = append(itemNames, name) + } + return reportSystems(cmd, itemNames) + }, + } systemReportCmd.Flags().String("name", "", "the system name") + return systemReportCmd } diff --git a/cmd/validateAutoinstalls.go b/cmd/validateAutoinstalls.go index e2c2a5c..e1c5c6d 100644 --- a/cmd/validateAutoinstalls.go +++ b/cmd/validateAutoinstalls.go @@ -9,26 +9,25 @@ import ( "github.com/spf13/cobra" ) -// validateAutoinstallsCmd represents the validateAutoinstalls command -var validateAutoinstallsCmd = &cobra.Command{ - Use: "validate-autoinstalls", - Short: "Autoinstall validation", - Long: `Validates the autoinstall files.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } +// NewValidateAutoinstallsCmd builds a command that represents the validateAutoinstalls action +func NewValidateAutoinstallsCmd() *cobra.Command { + validateAutoinstallsCmd := &cobra.Command{ + Use: "validate-autoinstalls", + Short: "Autoinstall validation", + Long: `Validates the autoinstall files.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } - eventId, err := Client.BackgroundValidateAutoinstallFiles() - if err != nil { - return err - } - fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) - return nil - }, -} - -func init() { - rootCmd.AddCommand(validateAutoinstallsCmd) + eventId, err := Client.BackgroundValidateAutoinstallFiles() + if err != nil { + return err + } + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) + return nil + }, + } + return validateAutoinstallsCmd } diff --git a/cmd/version.go b/cmd/version.go index 631cae2..03d73b9 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -10,28 +10,31 @@ import ( "runtime/debug" ) -// versionCmd represents the version command -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the Cobbler version", - Long: `Shows the Cobbler server version.`, - RunE: func(cmd *cobra.Command, args []string) error { - err := generateCobblerClient() - if err != nil { - return err - } - version, err := Client.ExtendedVersion() - if err != nil { - return err - } - clientVersion, cliVersion, _ := getClientVersion() - fmt.Fprintf(cmd.OutOrStdout(), "Cobbler %s\n", version.Version) - fmt.Fprintf(cmd.OutOrStdout(), " source: %s, %s\n", version.Gitstamp, version.Gitdate) - fmt.Fprintf(cmd.OutOrStdout(), " build time: %s\n", version.Builddate) - fmt.Fprintf(cmd.OutOrStdout(), " cli: %s\n", cliVersion) - fmt.Fprintf(cmd.OutOrStdout(), " client: %s\n", clientVersion) - return nil - }, +// NewVersionCmd builds a new command that represents the version action +func NewVersionCmd() *cobra.Command { + versionCmd := &cobra.Command{ + Use: "version", + Short: "Print the Cobbler version", + Long: `Shows the Cobbler server version.`, + RunE: func(cmd *cobra.Command, args []string) error { + err := generateCobblerClient() + if err != nil { + return err + } + version, err := Client.ExtendedVersion() + if err != nil { + return err + } + clientVersion, cliVersion, _ := getClientVersion() + fmt.Fprintf(cmd.OutOrStdout(), "Cobbler %s\n", version.Version) + fmt.Fprintf(cmd.OutOrStdout(), " source: %s, %s\n", version.Gitstamp, version.Gitdate) + fmt.Fprintf(cmd.OutOrStdout(), " build time: %s\n", version.Builddate) + fmt.Fprintf(cmd.OutOrStdout(), " cli: %s\n", cliVersion) + fmt.Fprintf(cmd.OutOrStdout(), " client: %s\n", clientVersion) + return nil + }, + } + return versionCmd } func getClientVersion() (string, string, error) { @@ -47,7 +50,3 @@ func getClientVersion() (string, string, error) { } return clientVersion, cliVersion, nil } - -func init() { - rootCmd.AddCommand(versionCmd) -} From 3f88b1388f23c18b19fe3baaa0754ceebaa7512e Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 10:55:49 +0100 Subject: [PATCH 04/17] Replicate: Fix event ID return message consistency --- cmd/replicate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/replicate.go b/cmd/replicate.go index 5ff6ee0..a995754 100644 --- a/cmd/replicate.go +++ b/cmd/replicate.go @@ -103,7 +103,7 @@ See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-replicate for if err != nil { return err } - fmt.Fprintf(cmd.OutOrStdout(), "EventID: %s\n", eventId) + fmt.Fprintf(cmd.OutOrStdout(), "Event ID: %s\n", eventId) return nil }, } From c1d05538c6200a16f113d8fd0a83c2e84ac3f732 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 10:56:37 +0100 Subject: [PATCH 05/17] Fail if explicitly given config file is not existing --- cmd/root.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 71d41ac..1032d53 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -110,10 +110,12 @@ func initConfig() { viper.AutomaticEnv() // read in environment variables that match // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - if verbose { - _, _ = fmt.Fprintln(os.Stdout, "Using config file:", viper.ConfigFileUsed()) - } + err := viper.ReadInConfig() + if cfgFile != "" { + cobra.CheckErr(err) + } + if verbose { + _, _ = fmt.Fprintln(os.Stdout, "Using config file:", viper.ConfigFileUsed()) } } From c93326e9b5c0c5c5394a6d5544f7dd7c0a70134f Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 11:40:59 +0100 Subject: [PATCH 06/17] Settings: Don't use os.exit to make code testable --- cmd/setting.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/setting.go b/cmd/setting.go index 73cee0d..b28d640 100644 --- a/cmd/setting.go +++ b/cmd/setting.go @@ -5,9 +5,9 @@ package cmd import ( + "errors" "fmt" "github.com/spf13/cobra" - "os" ) // NewSettingCmd builds a new command that represents the setting action @@ -41,8 +41,7 @@ func NewSettingEditCmd() *cobra.Command { return err } if !settings.AllowDynamicSettings { - fmt.Fprintln(cmd.OutOrStdout(), "Dynamic settings are turned off server-side!") - os.Exit(1) + return errors.New("dynamic settings are turned off server-side") } settingName, err := cmd.Flags().GetString("name") From 9a4378584a4a70aaf794ebb481a056500f7c581a Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 11:45:50 +0100 Subject: [PATCH 07/17] aclsetup: Mark flags according to server-side logic --- cmd/aclsetup.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/aclsetup.go b/cmd/aclsetup.go index 0027c10..1a89076 100644 --- a/cmd/aclsetup.go +++ b/cmd/aclsetup.go @@ -16,7 +16,6 @@ func NewAclSetupCmd() *cobra.Command { Use: "aclsetup", Short: "Adjust the access control list", Long: "Configures users/groups to run the Cobbler CLI as non-root.", - Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { err := generateCobblerClient() if err != nil { @@ -56,5 +55,7 @@ func NewAclSetupCmd() *cobra.Command { aclsetupCmd.Flags().String("addgroup", "", "give acls to this group") aclsetupCmd.Flags().String("removeuser", "", "remove acls from this user") aclsetupCmd.Flags().String("removegroup", "", "remove acls from this user") + aclsetupCmd.MarkFlagsMutuallyExclusive("adduser", "addgroup", "removeuser", "removegroup") + aclsetupCmd.MarkFlagsOneRequired("adduser", "addgroup", "removeuser", "removegroup") return aclsetupCmd } From 81475ca573fc18f3088d864b42b52eb4d2731619 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 15:14:12 +0100 Subject: [PATCH 08/17] Add missing --newname flags for rename and copy --- cmd/menu.go | 56 +++++++++++++++++++++++++++++++++++++++---------- cmd/metadata.go | 8 +++++++ cmd/root.go | 6 ++++-- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/cmd/menu.go b/cmd/menu.go index 14cb7e4..3d6ddc3 100644 --- a/cmd/menu.go +++ b/cmd/menu.go @@ -52,7 +52,7 @@ func updateMenuFromFlags(cmd *cobra.Command, menu *cobbler.Menu) error { } // NewMenuCmd builds a new command that represents the menu action -func NewMenuCmd() *cobra.Command { +func NewMenuCmd() (*cobra.Command, error) { menuCmd := &cobra.Command{ Use: "menu", Short: "Menu management", @@ -62,18 +62,30 @@ See https://cobbler.readthedocs.io/en/latest/cobbler.html#cobbler-menu for more _ = cmd.Help() }, } - menuCmd.AddCommand(NewMenuAddCmd()) - menuCmd.AddCommand(NewMenuCopyCmd()) + menuAddCmd, err := NewMenuAddCmd() + if err != nil { + return nil, err + } + menuCmd.AddCommand(menuAddCmd) + menuCopyCmd, err := NewMenuCopyCmd() + if err != nil { + return nil, err + } + menuCmd.AddCommand(menuCopyCmd) menuCmd.AddCommand(NewMenuEditCmd()) menuCmd.AddCommand(NewMenuFindCmd()) menuCmd.AddCommand(NewMenuListCmd()) menuCmd.AddCommand(NewMenuRemoveCmd()) - menuCmd.AddCommand(NewMenuRenameCmd()) + menuRenameCmd, err := NewMenuRenameCmd() + if err != nil { + return nil, err + } + menuCmd.AddCommand(menuRenameCmd) menuCmd.AddCommand(NewMenuReportCmd()) - return menuCmd + return menuCmd, nil } -func NewMenuAddCmd() *cobra.Command { +func NewMenuAddCmd() (*cobra.Command, error) { menuAddCmd := &cobra.Command{ Use: "add", Short: "add menu", @@ -107,10 +119,14 @@ func NewMenuAddCmd() *cobra.Command { } addCommonArgs(menuAddCmd) addStringFlags(menuAddCmd, menuStringFlagMetadata) - return menuAddCmd + err := menuAddCmd.MarkFlagRequired("name") + if err != nil { + return nil, err + } + return menuAddCmd, nil } -func NewMenuCopyCmd() *cobra.Command { +func NewMenuCopyCmd() (*cobra.Command, error) { menuCopyCmd := &cobra.Command{ Use: "copy", Short: "copy menu", @@ -151,8 +167,17 @@ func NewMenuCopyCmd() *cobra.Command { } addCommonArgs(menuCopyCmd) addStringFlags(menuCopyCmd, menuStringFlagMetadata) + addStringFlags(menuCopyCmd, copyRenameStringFlagMetadata) menuCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") - return menuCopyCmd + err := menuCopyCmd.MarkFlagRequired("name") + if err != nil { + return nil, err + } + err = menuCopyCmd.MarkFlagRequired("newname") + if err != nil { + return nil, err + } + return menuCopyCmd, nil } func NewMenuEditCmd() *cobra.Command { @@ -251,7 +276,7 @@ func NewMenuRemoveCmd() *cobra.Command { return menuRemoveCmd } -func NewMenuRenameCmd() *cobra.Command { +func NewMenuRenameCmd() (*cobra.Command, error) { menuRenameCmd := &cobra.Command{ Use: "rename", Short: "rename menu", @@ -292,8 +317,17 @@ func NewMenuRenameCmd() *cobra.Command { } addCommonArgs(menuRenameCmd) addStringFlags(menuRenameCmd, menuStringFlagMetadata) + addStringFlags(menuRenameCmd, copyRenameStringFlagMetadata) menuRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") - return menuRenameCmd + err := menuRenameCmd.MarkFlagRequired("name") + if err != nil { + return nil, err + } + err = menuRenameCmd.MarkFlagRequired("newname") + if err != nil { + return nil, err + } + return menuRenameCmd, nil } func reportMenus(cmd *cobra.Command, menuNames []string) error { diff --git a/cmd/metadata.go b/cmd/metadata.go index 92d2428..548d0b6 100644 --- a/cmd/metadata.go +++ b/cmd/metadata.go @@ -29,6 +29,14 @@ var commonStringSliceFlagMetadata = map[string]FlagMetadata[[]string]{ }, } +var copyRenameStringFlagMetadata = map[string]FlagMetadata[string]{ + "newname": { + Name: "newname", + DefaultValue: "", + Usage: "the new item name", + }, +} + var distroStringFlagMetadata = map[string]FlagMetadata[string]{ "kernel": { Name: "kernel", diff --git a/cmd/root.go b/cmd/root.go index 1032d53..1929d37 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -37,7 +37,7 @@ func NewRootCmd() *cobra.Command { // global flags rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobbler.yaml)") - rootCmd.Flags().BoolVar(&verbose, "verbose", false, "Whether or not to print debug messages from the CLI.") + rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "Whether or not to print debug messages from the CLI.") // Add sub commands rootCmd.AddCommand(NewAclSetupCmd()) @@ -51,7 +51,9 @@ func NewRootCmd() *cobra.Command { rootCmd.AddCommand(NewImageCmd()) rootCmd.AddCommand(NewImportCmd()) rootCmd.AddCommand(NewListCmd()) - rootCmd.AddCommand(NewMenuCmd()) + menuCmd, err := NewMenuCmd() + cobra.CheckErr(err) + rootCmd.AddCommand(menuCmd) rootCmd.AddCommand(NewMgmtClassCmd()) rootCmd.AddCommand(NewMkLoadersCmd()) rootCmd.AddCommand(NewPackageCmd()) From 03fc1788f9f9f4dfc5cad1fdc030fd9479672b37 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 16:43:06 +0100 Subject: [PATCH 09/17] Fix reporting of item type Package and File --- cmd/root.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index 1929d37..509dc47 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -156,6 +156,11 @@ func printStructured(cmd *cobra.Command, dataStruct interface{}) { printStructured(cmd, &baseItem) continue } + if fieldName == "Resource" { + baseResource := f.Interface().(cobbler.Resource) + printStructured(cmd, &baseResource) + continue + } if fieldName == "Interfaces" { // Skip and print at the end continue From c7c20f1ee22b3b1fc88626ea6d1057ea8e7cba8d Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 16:43:28 +0100 Subject: [PATCH 10/17] System: Add missing newname flag to copy action --- cmd/system.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/system.go b/cmd/system.go index 99d5d95..1951395 100644 --- a/cmd/system.go +++ b/cmd/system.go @@ -905,6 +905,7 @@ func NewSystemCopyCmd() *cobra.Command { addBoolFlags(systemCopyCmd, interfaceBoolFlagMetadata) addStringSliceFlags(systemCopyCmd, interfaceStringSliceFlagMetadata) // Other + addStringFlags(systemCopyCmd, copyRenameStringFlagMetadata) systemCopyCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") systemCopyCmd.Flags().String("interface", "", "the interface to operate on") systemCopyCmd.Flags().Bool("delete-interface", false, "delete the given interface (should be used with --interface)") @@ -1297,7 +1298,7 @@ func NewSystemRenameCmd() *cobra.Command { addBoolFlags(systemRenameCmd, interfaceBoolFlagMetadata) addStringSliceFlags(systemRenameCmd, interfaceStringSliceFlagMetadata) // Other - systemRenameCmd.Flags().String("newname", "", "the new system name") + addStringFlags(systemRenameCmd, copyRenameStringFlagMetadata) systemRenameCmd.Flags().Bool("in-place", false, "edit items in kopts or autoinstall without clearing the other items") systemRenameCmd.Flags().String("interface", "", "the interface to operate on") systemRenameCmd.Flags().Bool("delete-interface", false, "delete the given interface (should be used with --interface)") From bc4051869f8bfcee1a9b2b44f3705e20915d1a09 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 16:43:58 +0100 Subject: [PATCH 11/17] Fix incorrectly copy&pasted methods --- cmd/package.go | 2 +- cmd/profile.go | 2 +- cmd/repo.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/package.go b/cmd/package.go index 10eaed5..b8b80a4 100644 --- a/cmd/package.go +++ b/cmd/package.go @@ -335,7 +335,7 @@ func NewPackageRenameCmd() *cobra.Command { func reportPackages(cmd *cobra.Command, packageNames []string) error { for _, itemName := range packageNames { - repo, err := Client.GetRepo(itemName, false, false) + repo, err := Client.GetPackage(itemName, false, false) if err != nil { return err } diff --git a/cmd/profile.go b/cmd/profile.go index 6f0529f..452ba11 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -595,7 +595,7 @@ func NewProfileCopyCmd() *cobra.Command { if err != nil { return err } - err = Client.CopyDistro(profileHandle, profileNewName) + err = Client.CopyProfile(profileHandle, profileNewName) if err != nil { return err } diff --git a/cmd/repo.go b/cmd/repo.go index bfd74ed..8a4d698 100644 --- a/cmd/repo.go +++ b/cmd/repo.go @@ -430,7 +430,7 @@ func NewRepoRenameCmd() *cobra.Command { return err } // Get repo handle from the API - repoHandle, err := Client.GetMenuHandle(repoName) + repoHandle, err := Client.GetRepoHandle(repoName) if err != nil { return err } From 88bc010c9854fad309802dbd78d12c0ea57bcf4a Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 16:44:17 +0100 Subject: [PATCH 12/17] MgmtClass: Fix in-place flag access during creation --- cmd/mgmtclass.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/mgmtclass.go b/cmd/mgmtclass.go index 69b72db..d308081 100644 --- a/cmd/mgmtclass.go +++ b/cmd/mgmtclass.go @@ -12,9 +12,13 @@ import ( ) func updateMgmtClassFromFlags(cmd *cobra.Command, mgmtClass *cobbler.MgmtClass) error { - inPlace, err := cmd.Flags().GetBool("in-place") - if err != nil { - return err + var inPlace bool + var err error + if cmd.Flags().Lookup("in-place") != nil { + inPlace, err = cmd.Flags().GetBool("in-place") + if err != nil { + return err + } } cmd.Flags().Visit(func(flag *pflag.Flag) { if err != nil { From 7471da7c4b2c7930fd0f0961b6e601de7be5d762 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 16:44:30 +0100 Subject: [PATCH 13/17] File: Fix owner flag --- cmd/file.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/cmd/file.go b/cmd/file.go index 1e2776c..06e090f 100644 --- a/cmd/file.go +++ b/cmd/file.go @@ -83,17 +83,12 @@ func updateFileFromFlags(cmd *cobra.Command, file *cobbler.File) error { } file.Group = fileNewGroup case "owner": - if cmd.Flags().Lookup("owners-inherit").Changed { - file.Owners.IsInherited, err = cmd.Flags().GetBool("owners-inherit") - if err != nil { - return - } - } else { - file.Owners.Data, err = cmd.Flags().GetStringSlice("owners") - if err != nil { - return - } + var fileNewOwner string + fileNewOwner, err = cmd.Flags().GetString("owner") + if err != nil { + return } + file.Owner = fileNewOwner case "is-dir": var fileNewIsDir bool fileNewIsDir, err = cmd.Flags().GetBool("is-dir") From a847e63e8b54c85d25d5bd02947b1b69d2e1d319 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 20:03:52 +0100 Subject: [PATCH 14/17] Image: Fix object creation message --- cmd/image.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/image.go b/cmd/image.go index 7a16777..4d501bc 100644 --- a/cmd/image.go +++ b/cmd/image.go @@ -395,7 +395,7 @@ func NewImageAddCmd() *cobra.Command { if err != nil { return err } - fmt.Fprintf(cmd.OutOrStdout(), "System %s created\n", system.Name) + fmt.Fprintf(cmd.OutOrStdout(), "Image %s created\n", system.Name) return nil }, } From faac929b106ab559189d1138b6971ce3f67fa2dc Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 20:15:37 +0100 Subject: [PATCH 15/17] System: Skip interface edits if no interface is given --- cmd/system.go | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/cmd/system.go b/cmd/system.go index 1951395..f4ff70f 100644 --- a/cmd/system.go +++ b/cmd/system.go @@ -23,8 +23,8 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { deleteInterface := deleteInterfaceFlag != nil && deleteInterfaceFlag.Changed renameInterface := renameInterfaceFlag != nil && renameInterfaceFlag.Changed systemInterface, keyInMap := system.Interfaces[systemNewInterface] - if !keyInMap { - // Interface doesn't exist, so add a new one. + if systemNewInterface != "" && !keyInMap { + // Interface doesn't exist and non-empty string, so add a new one. // We cannot call CreateInterface because the system might not exist. system.Interfaces[systemNewInterface] = cobbler.Interface{} systemInterface = system.Interfaces[systemNewInterface] @@ -521,7 +521,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } system.SerialBaudRate = systemNewSerialBaudRate case "bonding-opts": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewBondingOpts string @@ -531,7 +531,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.BondingOpts = systemNewBondingOpts case "bridge-opts": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewBridgeOpts string @@ -541,7 +541,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.BridgeOpts = systemNewBridgeOpts case "cnames": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewCNames []string @@ -551,7 +551,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.CNAMEs = systemNewCNames case "connected-mode": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewConnectedMode bool @@ -561,7 +561,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.ConnectedMode = systemNewConnectedMode case "dhcp-tag": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewDhcpTag string @@ -571,7 +571,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.DHCPTag = systemNewDhcpTag case "dns-name": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewDnsName string @@ -581,7 +581,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.DNSName = systemNewDnsName case "if-gateway": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewIfGateway string @@ -591,7 +591,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.Gateway = systemNewIfGateway case "interface-master": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewInterfaceMaster string @@ -601,7 +601,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.InterfaceMaster = systemNewInterfaceMaster case "interface-type": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewInterfaceType string @@ -611,7 +611,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.InterfaceType = systemNewInterfaceType case "ip-address": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewIpAddress string @@ -621,7 +621,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.IPAddress = systemNewIpAddress case "ipv6-address": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewIpv6Address string @@ -631,7 +631,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.IPv6Address = systemNewIpv6Address case "ipv6-default-gateway": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewIpv6DefaultGateway string @@ -641,7 +641,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.IPv6DefaultGateway = systemNewIpv6DefaultGateway case "ipv6-mtu": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewIpv6Mtu string @@ -651,7 +651,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.IPv6MTU = systemNewIpv6Mtu case "ipv6-prefix": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewIpv6Prefix string @@ -661,7 +661,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.IPv6Prefix = systemNewIpv6Prefix case "ipv6-secondaries": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewIpv6Secondaries []string @@ -671,7 +671,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.IPv6Secondaries = systemNewIpv6Secondaries case "ipv6-static-routes": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewIpv6StaticRoutes []string @@ -681,7 +681,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.IPv6StaticRoutes = systemNewIpv6StaticRoutes case "mac-address": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewMacAddress string @@ -691,7 +691,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.MACAddress = systemNewMacAddress case "management": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewManagement bool @@ -701,7 +701,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.Management = systemNewManagement case "mtu": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewMtu string @@ -711,7 +711,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.MTU = systemNewMtu case "netmask": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewNetmask string @@ -721,7 +721,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.Netmask = systemNewNetmask case "static": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewStatic bool @@ -731,7 +731,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.Static = systemNewStatic case "static-routes": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewStaticRoutes []string @@ -741,7 +741,7 @@ func updateSystemFromFlags(cmd *cobra.Command, system *cobbler.System) error { } systemInterface.StaticRoutes = systemNewStaticRoutes case "virt-bridge": - if renameInterface || deleteInterface { + if renameInterface || deleteInterface || systemNewInterface == "" { return } var systemNewVirtBridge string From 7fd454711e8f59743c0a9ab63be2cc4e9902f4f3 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Mon, 4 Nov 2024 10:18:14 +0100 Subject: [PATCH 16/17] Update client to 0.5.5 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7884c39..374f586 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/cobbler/cli go 1.22 require ( - github.com/cobbler/cobblerclient v0.5.4 + github.com/cobbler/cobblerclient v0.5.5 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 diff --git a/go.sum b/go.sum index fcea715..68d5924 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/cobbler/cobblerclient v0.5.4 h1:ix+z9gwfUxv28ANz7giPGt4ICufR83rUm9E2q9dCwuw= -github.com/cobbler/cobblerclient v0.5.4/go.mod h1:n6b8fTUOlg7BdMl6FeifUm4Uk1JY6/tlTlOClV4x2Wc= +github.com/cobbler/cobblerclient v0.5.5 h1:sMd+j3IcW8atuAbwiJWOL+vriqxTPi5jxEg10TdQUc0= +github.com/cobbler/cobblerclient v0.5.5/go.mod h1:n6b8fTUOlg7BdMl6FeifUm4Uk1JY6/tlTlOClV4x2Wc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 9b355c31e5b2dc02fdb73809194b8768cabd68fa Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Thu, 31 Oct 2024 11:46:04 +0100 Subject: [PATCH 17/17] Testing: Add integration testsuite --- .github/workflows/coverage-upload.yml | 55 +++ .github/workflows/testing.yml | 70 ++++ .gitignore | 6 + Makefile | 6 + cmd/aclsetup_test.go | 76 +++++ cmd/buildiso_test.go | 117 +++++++ cmd/distro_test.go | 456 +++++++++++++++++++++++++ cmd/event_test.go | 87 +++++ cmd/file_test.go | 459 ++++++++++++++++++++++++++ cmd/hardlink_test.go | 38 +++ cmd/image_test.go | 454 +++++++++++++++++++++++++ cmd/import_test.go | 58 ++++ cmd/list_test.go | 38 +++ cmd/menu_test.go | 454 +++++++++++++++++++++++++ cmd/mgmtclass_test.go | 454 +++++++++++++++++++++++++ cmd/mkloaders_test.go | 38 +++ cmd/package_test.go | 454 +++++++++++++++++++++++++ cmd/profile_test.go | 455 +++++++++++++++++++++++++ cmd/replicate_test.go | 58 ++++ cmd/repo_test.go | 454 +++++++++++++++++++++++++ cmd/report_test.go | 38 +++ cmd/reposync_test.go | 70 ++++ cmd/setting_test.go | 60 ++++ cmd/signature_test.go | 92 ++++++ cmd/sync_test.go | 86 +++++ cmd/system_test.go | 455 +++++++++++++++++++++++++ cmd/testing.go | 20 ++ cmd/utils_test.go | 2 - cmd/validateAutoinstalls_test.go | 38 +++ cmd/version_test.go | 38 +++ testing/.cobbler.yaml | 3 + testing/compose.yml | 17 + testing/start.sh | 70 ++++ 33 files changed, 5274 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/coverage-upload.yml create mode 100644 .github/workflows/testing.yml create mode 100644 cmd/aclsetup_test.go create mode 100644 cmd/buildiso_test.go create mode 100644 cmd/distro_test.go create mode 100644 cmd/event_test.go create mode 100644 cmd/file_test.go create mode 100644 cmd/hardlink_test.go create mode 100644 cmd/image_test.go create mode 100644 cmd/import_test.go create mode 100644 cmd/list_test.go create mode 100644 cmd/menu_test.go create mode 100644 cmd/mgmtclass_test.go create mode 100644 cmd/mkloaders_test.go create mode 100644 cmd/package_test.go create mode 100644 cmd/profile_test.go create mode 100644 cmd/replicate_test.go create mode 100644 cmd/repo_test.go create mode 100644 cmd/report_test.go create mode 100644 cmd/reposync_test.go create mode 100644 cmd/setting_test.go create mode 100644 cmd/signature_test.go create mode 100644 cmd/sync_test.go create mode 100644 cmd/system_test.go create mode 100644 cmd/testing.go create mode 100644 cmd/validateAutoinstalls_test.go create mode 100644 cmd/version_test.go create mode 100644 testing/.cobbler.yaml create mode 100644 testing/compose.yml create mode 100755 testing/start.sh diff --git a/.github/workflows/coverage-upload.yml b/.github/workflows/coverage-upload.yml new file mode 100644 index 0000000..0ea36f0 --- /dev/null +++ b/.github/workflows/coverage-upload.yml @@ -0,0 +1,55 @@ +name: Coverage Upload + +on: + workflow_run: + workflows: [testing] + types: + - completed + +jobs: + run_tests: + runs-on: ubuntu-latest + steps: + # https://github.com/actions/github-script + # Based on: https://github.com/orgs/community/discussions/34652 + - name: 'Download artifact' + uses: actions/github-script@v7 + with: + script: | + let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "coverage-report" + })[0]; + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + let fs = require('fs'); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/coverage-report.zip`, Buffer.from(download.data)); + - name: 'Unzip artifact' + run: unzip coverage-report.zip + # https://github.com/actions/download-artifact + # - name: Download artifact + # id: download-artifact + # uses: actions/download-artifact@v4 + # with: + # run-id: ${{ github.event.workflow_run.id }} + # https://github.com/codacy/codacy-coverage-reporter-action + # - name: Run codacy-coverage-reporter + # uses: codacy/codacy-coverage-reporter-action@v1 + # with: + # project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + # coverage-reports: coverage.xml + - name: Publish Code Coverage Results + run: | + auth="--project-token ${{ secrets.CODACY_PROJECT_TOKEN }}" + commit_uuid="--commit-uuid ${{ github.event.workflow_run.head_sha }}" + + bash <(curl -Ls https://coverage.codacy.com/get.sh) report $auth $commit_uuid --force-coverage-parser go -r coverage.out --partial &&\ + bash <(curl -Ls https://coverage.codacy.com/get.sh) final $auth $commit_uuid \ No newline at end of file diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml new file mode 100644 index 0000000..a3fce4c --- /dev/null +++ b/.github/workflows/testing.yml @@ -0,0 +1,70 @@ +name: testing + +on: + push: + branches: + - 'main' + tags: + - 'v*' + pull_request: + +permissions: + contents: read + +jobs: + test: + name: Integration Tests (Cobbler ${{ matrix.cobbler_version }}) + runs-on: ubuntu-latest + strategy: + matrix: + cobbler_version: + # - d8f60bbf14a838c8c8a1dba98086b223e35fe70a # 3.3.0 - TypeError during import + - f5b0599acce32de4288c76e4f601aece0c664fed # 3.3.1 + # - 9044aa990a94752fa5bd5a24051adde099280bfa # 3.3.2 - Testing Docker Image broken + # - 5c498dbf2af6e3782b37605a477759e1aacc16b2 # 3.3.3 - Testing Docker Image broken + - 3ed865b79ce69fca7464e0957f4bcadcc9917a9d # 3.3.4 + - 718e3256a5989941e8a678404fdea07364255637 # 3.3.5 + - df356046f3cf27be62a61001b982d5983800cfd9 # 3.3.6 + fail-fast: false + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + id: go + - name: Install system dependencies + run: | + sudo apt-get install -y xorriso + - name: Get dependencies + run: | + go mod download + - name: Replace git version hash + run: | + sed -i "s/cobbler_commit=.*/cobbler_commit=${{ matrix.cobbler_version }}/" testing/start.sh + - name: Restore OS ISO + id: cache-iso-restore + uses: actions/cache/restore@v4 + with: + path: | + *.iso + key: ${{ runner.os }}-${{ matrix.cobbler_version }}-iso + - name: Make Test + run: | + make test + - name: Save OS ISO + id: cache-iso-save + uses: actions/cache/save@v4 + with: + path: | + *.iso + key: ${{ steps.cache-iso-restore.outputs.cache-primary-key }} + # https://github.com/actions/upload-artifact + - name: Upload coverage report to GH artifacts + if: matrix.cobbler_version == 'df356046f3cf27be62a61001b982d5983800cfd9' + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage.out + if-no-files-found: error diff --git a/.gitignore b/.gitignore index 654c4c8..96c5ae2 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,9 @@ docs/_build # goreleaser dist/ + +# Tests +testing/cobbler_source/ +extracted_iso_image/ +*.iso +coverage.out diff --git a/Makefile b/Makefile index 75d4845..916f247 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ BINARY_NAME=cobbler EXECUTOR?=docker +COBBLER_SERVER_URL=http://localhost:8081/cobbler_api +TEST?=$$(go list ./... |grep -v 'vendor') build: @echo "building package" @@ -28,6 +30,10 @@ run: go build -o ${BINARY_NAME} main.go ./${BINARY_NAME} +test: + @./testing/start.sh ${COBBLER_SERVER_URL} + go test -v -coverprofile="coverage.out" -covermode="atomic" $(TEST) + shell_completions: @mkdir -p config/completions/bash @mkdir -p config/completions/fish diff --git a/cmd/aclsetup_test.go b/cmd/aclsetup_test.go new file mode 100644 index 0000000..89d06ef --- /dev/null +++ b/cmd/aclsetup_test.go @@ -0,0 +1,76 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_AclSetupCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "adduser", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "aclsetup", "--adduser", "cobbler"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "addgroup", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "aclsetup", "--addgroup", "cobbler"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "removeuser", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "aclsetup", "--removeuser", "cobbler"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "removegroup", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "aclsetup", "--removegroup", "cobbler"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/buildiso_test.go b/cmd/buildiso_test.go new file mode 100644 index 0000000..d8d7f3c --- /dev/null +++ b/cmd/buildiso_test.go @@ -0,0 +1,117 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_BuildisoStandaloneCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "buildiso", "--standalone"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "airgapped", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "buildiso", "--airgapped"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} + +func Test_BuildisoNetinstallCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "systems", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "buildiso", "--systems", "test"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "nodns", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "buildiso", "--systems", "test", "--exclude-dns"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/distro_test.go b/cmd/distro_test.go new file mode 100644 index 0000000..6ec50ea --- /dev/null +++ b/cmd/distro_test.go @@ -0,0 +1,456 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createDistro(client cobbler.Client, name string) (*cobbler.Distro, error) { + distro := cobbler.NewDistro() + distro.Name = name + distro.Kernel = "/extracted_iso_image/install/vmlinuz" + distro.Initrd = "/extracted_iso_image/install/initrd.gz" + return client.CreateDistro(distro) +} + +func removeDistro(client cobbler.Client, name string) error { + return client.DeleteDistro(name) +} + +func Test_DistroAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "distro", "add", "--name", "test-plain", "--kernel", "/extracted_iso_image/install/vmlinuz", "--initrd", "/extracted_iso_image/install/initrd.gz"}}, + want: "Distro test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeDistro(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_DistroCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "distro", "copy", "--name", "distro-to-copy", "--newname", "copied-distro"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeDistro(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removeDistro(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createDistro(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetDistro(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_DistroEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "distro", "edit", "--name", "test-distro-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeDistro(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createDistro(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedDistro, err := Client.GetDistro(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedDistro.Comment != "testcomment" { + t.Fatal("distro update wasn't successful") + } + }) + } +} + +func Test_DistroFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "distro", "find", "--name", "test-distro-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + distroName := "test-distro-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeDistro(Client, distroName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createDistro(Client, distroName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, distroName) { + fmt.Println(stdoutString) + t.Fatal("distro not successfully found") + } + }) + } +} + +func Test_DistroListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "distro", "list"}}, + want: "distros:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("distro list marker not located in output") + } + }) + } +} + +func Test_DistroRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "distro", "remove", "--name", "test-distro-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createDistro(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("distro", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("distro not successfully removed") + } + }) + } +} + +func Test_DistroRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "distro", "rename", "--name", "test-distro-rename", "--newname", "test-distro-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + distroName := "test-distro-rename" + newDistroName := "test-distro-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeDistro(Client, newDistroName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createDistro(Client, distroName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("distro", distroName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("distro not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("distro", newDistroName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("distro not successfully renamed (new name not present)") + } + }) + } +} + +func Test_DistroReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "distro", "report", "--name", "test-distro-report"}}, + want: ": test-distro-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + distroName := "test-distro-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeDistro(Client, distroName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createDistro(Client, distroName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/event_test.go b/cmd/event_test.go new file mode 100644 index 0000000..12bb1ab --- /dev/null +++ b/cmd/event_test.go @@ -0,0 +1,87 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_EventStatusCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "event", "status", "--event-id", "garbage"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + if err == nil { + t.Fatal("expected error, got none") + } + if !strings.Contains(err.Error(), "no event with that id") { + t.Fatal("server didn't complain about garbage event id") + } +} + +func Test_EventListCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "event", "list"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "Time (last transitioned)") { + fmt.Println(stdoutString) + t.Fatal("no table header with time present") + } +} + +func Test_EventLogCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "event", "log", "--event-id", "garbage"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "?") { + fmt.Println(stdoutString) + t.Fatal("server didn't complain about garbage event id") + } +} diff --git a/cmd/file_test.go b/cmd/file_test.go new file mode 100644 index 0000000..c35b3c3 --- /dev/null +++ b/cmd/file_test.go @@ -0,0 +1,459 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createFile(client cobbler.Client, name string) (*cobbler.File, error) { + file := cobbler.NewFile() + file.Name = name + file.Path = "/my/custom/folder" + file.Owner = "root" + file.Group = "root" + file.Mode = "0755" + file.IsDir = true + return client.CreateFile(file) +} + +func removeFile(client cobbler.Client, name string) error { + return client.DeleteFile(name) +} + +func Test_FileAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "file", "add", "--name", "test-plain", "--path", "/my/custom/folder", "--group", "root", "--owner", "root", "--mode", "0755", "--is-dir", "true"}}, + want: "File test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeFile(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_FileCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "file", "copy", "--name", "file-to-copy", "--newname", "copied-file"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeFile(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removeFile(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createFile(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetFile(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_FileEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "file", "edit", "--name", "test-file-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeFile(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createFile(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedFile, err := Client.GetFile(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedFile.Comment != "testcomment" { + t.Fatal("file update wasn't successful") + } + }) + } +} + +func Test_FileFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "file", "find", "--name", "test-file-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + fileName := "test-file-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeFile(Client, fileName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createFile(Client, fileName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, fileName) { + fmt.Println(stdoutString) + t.Fatal("file not successfully found") + } + }) + } +} + +func Test_FileListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "file", "list"}}, + want: "files:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("file list marker not located in output") + } + }) + } +} + +func Test_FileRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "file", "remove", "--name", "test-file-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createFile(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("file", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("file not successfully removed") + } + }) + } +} + +func Test_FileRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "file", "rename", "--name", "test-file-rename", "--newname", "test-file-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + fileName := "test-file-rename" + newFileName := "test-file-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeFile(Client, newFileName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createFile(Client, fileName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("file", fileName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("file not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("file", newFileName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("file not successfully renamed (new name not present)") + } + }) + } +} + +func Test_FileReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "file", "report", "--name", "test-file-report"}}, + want: ": test-file-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + fileName := "test-file-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeFile(Client, fileName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createFile(Client, fileName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/hardlink_test.go b/cmd/hardlink_test.go new file mode 100644 index 0000000..5c491ca --- /dev/null +++ b/cmd/hardlink_test.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_HardlinkCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "hardlink"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "Event ID:") { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } +} diff --git a/cmd/image_test.go b/cmd/image_test.go new file mode 100644 index 0000000..5959231 --- /dev/null +++ b/cmd/image_test.go @@ -0,0 +1,454 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createImage(client cobbler.Client, name string) (*cobbler.Image, error) { + image := cobbler.NewImage() + image.Name = name + return client.CreateImage(image) +} + +func removeImage(client cobbler.Client, name string) error { + return client.DeleteImage(name) +} + +func Test_ImageAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "image", "add", "--name", "test-plain"}}, + want: "Image test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeImage(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_ImageCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "image", "copy", "--name", "image-to-copy", "--newname", "copied-image"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeImage(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removeImage(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createImage(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetImage(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_ImageEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "image", "edit", "--name", "test-image-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeImage(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createImage(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedImage, err := Client.GetImage(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedImage.Comment != "testcomment" { + t.Fatal("image update wasn't successful") + } + }) + } +} + +func Test_ImageFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "image", "find", "--name", "test-image-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + imageName := "test-image-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeImage(Client, imageName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createImage(Client, imageName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, imageName) { + fmt.Println(stdoutString) + t.Fatal("finding the image was unsuccessful") + } + }) + } +} + +func Test_ImageListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "image", "list"}}, + want: "images:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("image list marker not located in output") + } + }) + } +} + +func Test_ImageRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "image", "remove", "--name", "test-image-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createImage(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("image", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("image not successfully removed") + } + }) + } +} + +func Test_ImageRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "image", "rename", "--name", "test-image-rename", "--newname", "test-image-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + imageName := "test-image-rename" + newImageName := "test-image-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeImage(Client, newImageName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createImage(Client, imageName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("image", imageName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("image not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("image", newImageName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("image not successfully renamed (new name not present)") + } + }) + } +} + +func Test_ImageReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "image", "report", "--name", "test-image-report"}}, + want: ": test-image-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + imageName := "test-image-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeImage(Client, imageName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createImage(Client, imageName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/import_test.go b/cmd/import_test.go new file mode 100644 index 0000000..dc87b27 --- /dev/null +++ b/cmd/import_test.go @@ -0,0 +1,58 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_ImportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "import"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/list_test.go b/cmd/list_test.go new file mode 100644 index 0000000..1483d1b --- /dev/null +++ b/cmd/list_test.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_ListCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "list"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !(strings.Contains(stdoutString, "distros:") && strings.Contains(stdoutString, "profiles")) { + fmt.Println(stdoutString) + t.Fatal("no heading for distros and profiles present") + } +} diff --git a/cmd/menu_test.go b/cmd/menu_test.go new file mode 100644 index 0000000..4f6ad2f --- /dev/null +++ b/cmd/menu_test.go @@ -0,0 +1,454 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createMenu(client cobbler.Client, name string) (*cobbler.Menu, error) { + menu := cobbler.NewMenu() + menu.Name = name + return client.CreateMenu(menu) +} + +func removeMenu(client cobbler.Client, name string) error { + return client.DeleteMenu(name) +} + +func Test_MenuAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "menu", "add", "--name", "test-plain"}}, + want: "Menu test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMenu(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_MenuCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "menu", "copy", "--name", "menu-to-copy", "--newname", "copied-menu"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMenu(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removeMenu(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMenu(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetMenu(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_MenuEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "menu", "edit", "--name", "test-menu-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMenu(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMenu(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedMenu, err := Client.GetMenu(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedMenu.Comment != "testcomment" { + t.Fatal("menu update wasn't successful") + } + }) + } +} + +func Test_MenuFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "menu", "find", "--name", "test-menu-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + menuName := "test-menu-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMenu(Client, menuName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMenu(Client, menuName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, menuName) { + fmt.Println(stdoutString) + t.Fatal("menu not successfully found") + } + }) + } +} + +func Test_MenuListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "menu", "list"}}, + want: "menus:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("menu list marker not located in output") + } + }) + } +} + +func Test_MenuRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "menu", "remove", "--name", "test-menu-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createMenu(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("menu", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("menu not successfully removed") + } + }) + } +} + +func Test_MenuRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "menu", "rename", "--name", "test-menu-rename", "--newname", "test-menu-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + menuName := "test-menu-rename" + newMenuName := "test-menu-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMenu(Client, newMenuName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMenu(Client, menuName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("menu", menuName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("menu not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("menu", newMenuName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("menu not successfully renamed (new name not present)") + } + }) + } +} + +func Test_MenuReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "menu", "report", "--name", "test-menu-report"}}, + want: ": test-menu-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + menuName := "test-menu-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMenu(Client, menuName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMenu(Client, menuName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/mgmtclass_test.go b/cmd/mgmtclass_test.go new file mode 100644 index 0000000..e0f71dd --- /dev/null +++ b/cmd/mgmtclass_test.go @@ -0,0 +1,454 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createMgmtClass(client cobbler.Client, name string) (*cobbler.MgmtClass, error) { + mgmtclass := cobbler.NewMgmtClass() + mgmtclass.Name = name + return client.CreateMgmtClass(mgmtclass) +} + +func removeMgmtClass(client cobbler.Client, name string) error { + return client.DeleteMgmtClass(name) +} + +func Test_MgmtClassAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "mgmtclass", "add", "--name", "test-plain"}}, + want: "Mgmtclass test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMgmtClass(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_MgmtClassCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "mgmtclass", "copy", "--name", "mgmtclass-to-copy", "--newname", "copied-mgmtclass"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMgmtClass(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removeMgmtClass(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMgmtClass(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetMgmtClass(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_MgmtClassEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "mgmtclass", "edit", "--name", "test-mgmtclass-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMgmtClass(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMgmtClass(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedMgmtClass, err := Client.GetMgmtClass(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedMgmtClass.Comment != "testcomment" { + t.Fatal("mgmtclass update wasn't successful") + } + }) + } +} + +func Test_MgmtClassFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "mgmtclass", "find", "--name", "test-mgmtclass-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + mgmtclassName := "test-mgmtclass-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMgmtClass(Client, mgmtclassName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMgmtClass(Client, mgmtclassName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, mgmtclassName) { + fmt.Println(stdoutString) + t.Fatal("mgmtclass not successfully found") + } + }) + } +} + +func Test_MgmtClassListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "mgmtclass", "list"}}, + want: "mgmtclasses:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("mgmtclass list marker not located in output") + } + }) + } +} + +func Test_MgmtClassRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "mgmtclass", "remove", "--name", "test-mgmtclass-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createMgmtClass(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("mgmtclass", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("mgmtclass not successfully removed") + } + }) + } +} + +func Test_MgmtClassRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "mgmtclass", "rename", "--name", "test-mgmtclass-rename", "--newname", "test-mgmtclass-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + mgmtclassName := "test-mgmtclass-rename" + newMgmtClassName := "test-mgmtclass-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMgmtClass(Client, newMgmtClassName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMgmtClass(Client, mgmtclassName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("mgmtclass", mgmtclassName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("mgmtclass not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("mgmtclass", newMgmtClassName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("mgmtclass not successfully renamed (new name not present)") + } + }) + } +} + +func Test_MgmtClassReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "mgmtclass", "report", "--name", "test-mgmtclass-report"}}, + want: ": test-mgmtclass-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + mgmtclassName := "test-mgmtclass-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeMgmtClass(Client, mgmtclassName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createMgmtClass(Client, mgmtclassName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/mkloaders_test.go b/cmd/mkloaders_test.go new file mode 100644 index 0000000..e330ef5 --- /dev/null +++ b/cmd/mkloaders_test.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_MkLoaders(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "mkloaders"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "Event ID:") { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } +} diff --git a/cmd/package_test.go b/cmd/package_test.go new file mode 100644 index 0000000..3d55d93 --- /dev/null +++ b/cmd/package_test.go @@ -0,0 +1,454 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createPackage(client cobbler.Client, name string) (*cobbler.Package, error) { + linuxpackage := cobbler.NewPackage() + linuxpackage.Name = name + return client.CreatePackage(linuxpackage) +} + +func removePackage(client cobbler.Client, name string) error { + return client.DeletePackage(name) +} + +func Test_PackageAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "package", "add", "--name", "test-plain"}}, + want: "Package test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removePackage(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_PackageCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "package", "copy", "--name", "package-to-copy", "--newname", "copied-package"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removePackage(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removePackage(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createPackage(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetPackage(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_PackageEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "package", "edit", "--name", "test-package-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removePackage(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createPackage(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedPackage, err := Client.GetPackage(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedPackage.Comment != "testcomment" { + t.Fatal("package update wasn't successful") + } + }) + } +} + +func Test_PackageFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "package", "find", "--name", "test-package-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + packageName := "test-package-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removePackage(Client, packageName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createPackage(Client, packageName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, packageName) { + fmt.Println(stdoutString) + t.Fatal("package not successfully found") + } + }) + } +} + +func Test_PackageListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "package", "list"}}, + want: "packages:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("package list marker not located in output") + } + }) + } +} + +func Test_PackageRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "package", "remove", "--name", "test-package-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createPackage(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("package", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("package not successfully removed") + } + }) + } +} + +func Test_PackageRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "package", "rename", "--name", "test-package-rename", "--newname", "test-package-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + packageName := "test-package-rename" + newPackageName := "test-package-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removePackage(Client, newPackageName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createPackage(Client, packageName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("package", packageName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("package not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("package", newPackageName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("package not successfully renamed (new name not present)") + } + }) + } +} + +func Test_PackageReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "package", "report", "--name", "test-package-report"}}, + want: ": test-package-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + packageName := "test-package-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removePackage(Client, packageName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createPackage(Client, packageName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/profile_test.go b/cmd/profile_test.go new file mode 100644 index 0000000..31d7993 --- /dev/null +++ b/cmd/profile_test.go @@ -0,0 +1,455 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createProfile(client cobbler.Client, name string) (*cobbler.Profile, error) { + profile := cobbler.NewProfile() + profile.Name = name + profile.Distro = "Ubuntu-20.04-x86_64" + return client.CreateProfile(profile) +} + +func removeProfile(client cobbler.Client, name string) error { + return client.DeleteProfile(name) +} + +func Test_ProfileAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "profile", "add", "--name", "test-plain", "--distro", "Ubuntu-20.04-x86_64"}}, + want: "Profile test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeProfile(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_ProfileCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "profile", "copy", "--name", "profile-to-copy", "--newname", "copied-profile"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeProfile(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removeProfile(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createProfile(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetProfile(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_ProfileEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "profile", "edit", "--name", "test-profile-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeProfile(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createProfile(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedProfile, err := Client.GetProfile(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedProfile.Comment != "testcomment" { + t.Fatal("profile update wasn't successful") + } + }) + } +} + +func Test_ProfileFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "profile", "find", "--name", "test-profile-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + profileName := "test-profile-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeProfile(Client, profileName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createProfile(Client, profileName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, profileName) { + fmt.Println(stdoutString) + t.Fatal("profile not successfully found") + } + }) + } +} + +func Test_ProfileListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "profile", "list"}}, + want: "profiles:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("profile list marker not located in output") + } + }) + } +} + +func Test_ProfileRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "profile", "remove", "--name", "test-profile-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createProfile(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("profile", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("profile not successfully removed") + } + }) + } +} + +func Test_ProfileRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "profile", "rename", "--name", "test-profile-rename", "--newname", "test-profile-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + profileName := "test-profile-rename" + newProfileName := "test-profile-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeProfile(Client, newProfileName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createProfile(Client, profileName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("profile", profileName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("profile not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("profile", newProfileName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("profile not successfully renamed (new name not present)") + } + }) + } +} + +func Test_ProfileReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "profile", "report", "--name", "test-profile-report"}}, + want: ": test-profile-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + profileName := "test-profile-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeProfile(Client, profileName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createProfile(Client, profileName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/replicate_test.go b/cmd/replicate_test.go new file mode 100644 index 0000000..2992646 --- /dev/null +++ b/cmd/replicate_test.go @@ -0,0 +1,58 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_ReplicateCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "replicate"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/repo_test.go b/cmd/repo_test.go new file mode 100644 index 0000000..f767d94 --- /dev/null +++ b/cmd/repo_test.go @@ -0,0 +1,454 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createRepo(client cobbler.Client, name string) (*cobbler.Repo, error) { + repo := cobbler.NewRepo() + repo.Name = name + return client.CreateRepo(repo) +} + +func removeRepo(client cobbler.Client, name string) error { + return client.DeleteRepo(name) +} + +func Test_RepoAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "repo", "add", "--name", "test-plain"}}, + want: "Repo test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeRepo(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_RepoCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "repo", "copy", "--name", "repo-to-copy", "--newname", "copied-repo"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeRepo(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removeRepo(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createRepo(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetRepo(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_RepoEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "repo", "edit", "--name", "test-repo-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeRepo(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createRepo(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedRepo, err := Client.GetRepo(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedRepo.Comment != "testcomment" { + t.Fatal("repo update wasn't successful") + } + }) + } +} + +func Test_RepoFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "repo", "find", "--name", "test-repo-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + repoName := "test-repo-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeRepo(Client, repoName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createRepo(Client, repoName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, repoName) { + fmt.Println(stdoutString) + t.Fatal("repo not successfully found") + } + }) + } +} + +func Test_RepoListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "repo", "list"}}, + want: "repos:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("repo list marker not located in output") + } + }) + } +} + +func Test_RepoRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "repo", "remove", "--name", "test-repo-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createRepo(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("repo", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("repo not successfully removed") + } + }) + } +} + +func Test_RepoRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "repo", "rename", "--name", "test-repo-rename", "--newname", "test-repo-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + repoName := "test-repo-rename" + newRepoName := "test-repo-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeRepo(Client, newRepoName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createRepo(Client, repoName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("repo", repoName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("repo not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("repo", newRepoName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("repo not successfully renamed (new name not present)") + } + }) + } +} + +func Test_RepoReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "repo", "report", "--name", "test-repo-report"}}, + want: ": test-repo-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + repoName := "test-repo-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeRepo(Client, repoName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createRepo(Client, repoName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/report_test.go b/cmd/report_test.go new file mode 100644 index 0000000..0ef2bb3 --- /dev/null +++ b/cmd/report_test.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_ReportCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "report"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !(strings.Contains(stdoutString, "distros:") && strings.Contains(stdoutString, "profiles")) { + fmt.Println(stdoutString) + t.Fatal("no heading for distros and profiles present") + } +} diff --git a/cmd/reposync_test.go b/cmd/reposync_test.go new file mode 100644 index 0000000..2e1bdeb --- /dev/null +++ b/cmd/reposync_test.go @@ -0,0 +1,70 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_ReposyncCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "reposync"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "tries", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "reposync", "--tries", "3"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "nofail", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "reposync", "--no-fail"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/setting_test.go b/cmd/setting_test.go new file mode 100644 index 0000000..29744fe --- /dev/null +++ b/cmd/setting_test.go @@ -0,0 +1,60 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_SettingEditCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "setting", "edit"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + if err == nil { + t.Fatal("expected error, got none") + } + if err.Error() != "dynamic settings are turned off server-side" { + t.Fatalf("expected dynamic settings are to be turned off server-side, got %s", err.Error()) + } +} + +func Test_SettingReportCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "setting", "report"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "scm_track_enabled") { + fmt.Println(stdoutString) + t.Fatal("Expected setting couldn't be found") + } +} diff --git a/cmd/signature_test.go b/cmd/signature_test.go new file mode 100644 index 0000000..fbd07eb --- /dev/null +++ b/cmd/signature_test.go @@ -0,0 +1,92 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_SignatureReloadCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "signature", "reload"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "This functionality cannot be used in the new CLI") { + fmt.Println(stdoutString) + t.Fatal("No missing feature message present") + } +} + +func Test_SignatureReportCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "signature", "report"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "Currently loaded signatures") { + fmt.Println(stdoutString) + t.Fatal("No report header present") + } +} + +func Test_SignatureUpdateCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "signature", "update"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "Event ID:") { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } +} diff --git a/cmd/sync_test.go b/cmd/sync_test.go new file mode 100644 index 0000000..44028be --- /dev/null +++ b/cmd/sync_test.go @@ -0,0 +1,86 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" + "time" +) + +func Test_SyncCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "sync"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "dns", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "sync", "--dns"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "dhcp", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "sync", "--dhcp"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "dhcpdns", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "sync", "--dns", "--dhcp"}}, + want: "Event ID:", + wantErr: false, + }, + { + name: "systems", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "sync", "--systems", "a.b.c,a.d.c"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + + // Cleanup - Sleep after each test to let dhcpd restart properly + time.Sleep(1 * time.Second) + }) + } +} diff --git a/cmd/system_test.go b/cmd/system_test.go new file mode 100644 index 0000000..6264d57 --- /dev/null +++ b/cmd/system_test.go @@ -0,0 +1,455 @@ +package cmd + +import ( + "bytes" + "fmt" + cobbler "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func createSystem(client cobbler.Client, name string) (*cobbler.System, error) { + system := cobbler.NewSystem() + system.Name = name + system.Profile = "Ubuntu-20.04-x86_64" + return client.CreateSystem(system) +} + +func removeSystem(client cobbler.Client, name string) error { + return client.DeleteSystem(name) +} + +func Test_SystemAddCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "system", "add", "--name", "test-plain", "--profile", "Ubuntu-20.04-x86_64"}}, + want: "System test-plain created", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeSystem(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("Item creation message missing") + } + }) + } +} + +func Test_SystemCopyCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "system", "copy", "--name", "system-to-copy", "--newname", "copied-system"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeSystem(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + cleanupErr = removeSystem(Client, tt.args.command[7]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createSystem(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + _, err = Client.GetSystem(tt.args.command[7], false, false) + cobbler.FailOnError(t, err) + }) + } +} + +func Test_SystemEditCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "system", "edit", "--name", "test-system-edit", "--comment", "testcomment"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeSystem(Client, tt.args.command[5]) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createSystem(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + updatedSystem, err := Client.GetSystem(tt.args.command[5], false, false) + cobbler.FailOnError(t, err) + if updatedSystem.Comment != "testcomment" { + t.Fatal("system update wasn't successful") + } + }) + } +} + +func Test_SystemFindCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "system", "find", "--name", "test-system-find"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + systemName := "test-system-find" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeSystem(Client, systemName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createSystem(Client, systemName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, systemName) { + fmt.Println(stdoutString) + t.Fatal("system not successfully found") + } + }) + } +} + +func Test_SystemListCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "system", "list"}}, + want: "systems:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("system list marker not located in output") + } + }) + } +} + +func Test_SystemRemoveCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "system", "remove", "--name", "test-system-remove"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Arrange + setupClient(t) + _, err := createSystem(Client, tt.args.command[5]) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + result, err := Client.HasItem("system", tt.args.command[5]) + cobbler.FailOnError(t, err) + if result { + // A missing item means we get "false", as such we error when we find an item. + t.Fatal("system not successfully removed") + } + }) + } +} + +func Test_SystemRenameCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "system", "rename", "--name", "test-system-rename", "--newname", "test-system-renamed"}}, + want: "Event ID:", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + systemName := "test-system-rename" + newSystemName := "test-system-renamed" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeSystem(Client, newSystemName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createSystem(Client, systemName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + FailOnNonEmptyStream(t, stdout) + resultOldName, err := Client.HasItem("system", systemName) + cobbler.FailOnError(t, err) + if resultOldName { + t.Fatal("system not successfully renamed (old name present)") + } + resultNewName, err := Client.HasItem("system", newSystemName) + cobbler.FailOnError(t, err) + if !resultNewName { + t.Fatal("system not successfully renamed (new name not present)") + } + }) + } +} + +func Test_SystemReportCmd(t *testing.T) { + type args struct { + command []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "plain", + args: args{command: []string{"--config", "../testing/.cobbler.yaml", "system", "report", "--name", "test-system-report"}}, + want: ": test-system-report", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Cleanup + systemName := "test-system-report" + var err error + defer func() { + // Client is initialized since this is the cleanup + cleanupErr := removeSystem(Client, systemName) + cobbler.FailOnError(t, cleanupErr) + }() + // Arrange + setupClient(t) + _, err = createSystem(Client, systemName) + cobbler.FailOnError(t, err) + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs(tt.args.command) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err = rootCmd.Execute() + + // Assert + cobbler.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, tt.want) { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } + }) + } +} diff --git a/cmd/testing.go b/cmd/testing.go new file mode 100644 index 0000000..3ecb48b --- /dev/null +++ b/cmd/testing.go @@ -0,0 +1,20 @@ +package cmd + +import ( + "bytes" + cobbler "github.com/cobbler/cobblerclient" + "testing" +) + +func setupClient(t *testing.T) { + cfgFile = "../testing/.cobbler.yaml" + initConfig() + err := generateCobblerClient() + cobbler.FailOnError(t, err) +} + +func FailOnNonEmptyStream(t *testing.T, buffer *bytes.Buffer) { + if buffer.Available() > 0 { + t.Fatal("stream wasn't empty!") + } +} diff --git a/cmd/utils_test.go b/cmd/utils_test.go index c743d63..a82235f 100644 --- a/cmd/utils_test.go +++ b/cmd/utils_test.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "reflect" "testing" "time" @@ -26,7 +25,6 @@ func Test_covertFloatToTime(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := covertFloatToUtcTime(tt.args.t) - fmt.Println(got) if (err != nil) != tt.wantErr { t.Errorf("covertFloatToTime() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/cmd/validateAutoinstalls_test.go b/cmd/validateAutoinstalls_test.go new file mode 100644 index 0000000..d80f24c --- /dev/null +++ b/cmd/validateAutoinstalls_test.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_ValidateAutoinstallsCmd(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "validate-autoinstalls"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "Event ID:") { + fmt.Println(stdoutString) + t.Fatal("No Event ID present") + } +} diff --git a/cmd/version_test.go b/cmd/version_test.go new file mode 100644 index 0000000..ac86d73 --- /dev/null +++ b/cmd/version_test.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/cobbler/cobblerclient" + "github.com/spf13/cobra" + "io" + "strings" + "testing" +) + +func Test_VersionCommand(t *testing.T) { + // Arrange + cobra.OnInitialize(initConfig, setupLogger) + rootCmd := NewRootCmd() + rootCmd.SetArgs([]string{"--config", "../testing/.cobbler.yaml", "version"}) + stdout := bytes.NewBufferString("") + stderr := bytes.NewBufferString("") + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + // Act + err := rootCmd.Execute() + + // Assert + cobblerclient.FailOnError(t, err) + FailOnNonEmptyStream(t, stderr) + stdoutBytes, err := io.ReadAll(stdout) + if err != nil { + t.Fatal(err) + } + stdoutString := string(stdoutBytes) + if !strings.Contains(stdoutString, "source: ?, ?") { + fmt.Println(stdoutString) + t.Fatal("CLI version not part of the return string") + } +} diff --git a/testing/.cobbler.yaml b/testing/.cobbler.yaml new file mode 100644 index 0000000..6531712 --- /dev/null +++ b/testing/.cobbler.yaml @@ -0,0 +1,3 @@ +server_url: "http://127.0.0.1:8081/cobbler_api" +server_username: "cobbler" +server_password: "cobbler" diff --git a/testing/compose.yml b/testing/compose.yml new file mode 100644 index 0000000..f02d3f3 --- /dev/null +++ b/testing/compose.yml @@ -0,0 +1,17 @@ +services: + cobbler: + image: cobbler-dev + container_name: cobbler-dev + privileged: true # Required for Cobbler 3.3.2 and newer + volumes: + - ./cobbler_source:/code + - ../extracted_iso_image:/extracted_iso_image + ports: + - 8081:80 + # We chmod the code, otherwise some files are read-only and cannot be cleaned up: + command: bash -c " + /code/docker/develop/scripts/setup-supervisor.sh && + chmod -R o+w /code && + cobbler import --name Ubuntu-20.04 --breed ubuntu --path /extracted_iso_image/ && + tail -F /dev/null + " diff --git a/testing/start.sh b/testing/start.sh new file mode 100755 index 0000000..1d75463 --- /dev/null +++ b/testing/start.sh @@ -0,0 +1,70 @@ +#! /bin/bash + +# Requires xorriso (sudo apt-get install -y xorriso, sudo yum install xorriso -y, or sudo zypper install -y xorriso) +if [ -z "$1" ] + then + echo "No cobbler server url supplied" +fi + +cobbler_commit=df356046f3cf27be62a61001b982d5983800cfd9 # 3.3.6 as of 2024-10-09 +cobbler_branch=release33 +iso_url=https://cdimage.ubuntu.com/ubuntu-legacy-server/releases/20.04/release/ubuntu-20.04.1-legacy-server-amd64.iso +iso_os=ubuntu +valid_iso_checksum=00a9d46306fbe9beb3581853a289490bc231c51f +iso_filename=$(echo ${iso_url##*/}) +valid_extracted_iso_checksum=dd0b3148e1f071fb86aee4b0395fd63b +valid_git_checksum=6c9511b26946dd3f1f072b9f40eaeccf # master as of 4/2/2022 + +[ -d "./testing/cobbler_source" ] && git_checksum=$(find ./testing/cobbler_source/ -type f -exec md5sum {} \; | sort -k 2 | md5sum | awk '{print $1}') +if [ -d "./testing/cobbler_source" ] && [ $git_checksum == $valid_git_checksum ]; then + echo "Cobbler code already cloned and the correct version is checked out" +else + rm -rf ./testing/cobbler_source + git clone --shallow-since="2021-09-01" https://github.com/cobbler/cobbler.git -b $cobbler_branch testing/cobbler_source + cd ./testing/cobbler_source + printf "Changing to version of Cobbler being tested.\n\n" + git checkout $cobbler_commit > /dev/null 2>&1 + rm -rf .git # remove .git dir so the checksum is consistent + cd - +fi + +echo $(pwd) +if [ -f "$iso_filename" ] && [ $(sha1sum $iso_filename | awk '{print $1}') == "$valid_iso_checksum" ]; then + echo "ISO already downloaded" +else + rm $iso_filename + wget $iso_url +fi + +extracted_iso_checksum=$(find extracted_iso_image -type f -exec md5sum {} \; | sort -k 2 | md5sum | awk '{print $1}') +if [ -d "extracted_iso_image" ] && [ $extracted_iso_checksum == $valid_extracted_iso_checksum ]; then + echo "ISO already extracted" +else + xorriso -osirrox on -indev $iso_filename -extract / extracted_iso_image +fi + +docker build -f ./testing/cobbler_source/docker/develop/develop.dockerfile -t cobbler-dev . +docker compose -f testing/compose.yml up -d + +SERVER_URL=$1 +printf "### Waiting for Cobbler to become available on ${SERVER_URL} \n\n" + +attempt_counter=0 +max_attempts=48 + +until $(curl --connect-timeout 1 --output /dev/null --silent ${SERVER_URL}); do + if [ ${attempt_counter} -eq ${max_attempts} ];then + echo "Max attempts reached" + # Debug logs + docker compose -f ./testing/compose.yml logs + exit 1 + fi + + attempt_counter=$(($attempt_counter+1)) + sleep 5 +done + +# Sleep 10 seconds to let the "cobbler import" succeed +sleep 10 + +docker compose -f testing/compose.yml logs \ No newline at end of file