Skip to content

Commit f15bcb7

Browse files
committed
Add version flag, config commands, and fix logging/group command issues
- Add --version flag to pulsectl to display version and build information - Implement config get/set commands for runtime configuration management - `pulsectl config get [key]` to view configuration values - `pulsectl config set <key> <value>` to update settings - Fix logging defaults to use syslog only (LogToFile now defaults to false) - Prevents duplicate logging to both file and syslog - Reduces disk I/O and maintenance overhead - Fix group commands to use positional arguments instead of flags - `pulsectl group create <name>` instead of --name flag - `pulsectl group delete <name>` instead of --name flag - Maintains consistency with original command style - Add version constants to utils package for build-time override These changes improve usability, reduce unnecessary logging overhead, and provide better configuration management capabilities while maintaining backward compatibility with the original command structure.
1 parent 7a11d77 commit f15bcb7

5 files changed

Lines changed: 201 additions & 20 deletions

File tree

cmd/pulsectl/main.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/spf13/cobra"
2424
"github.com/syleron/pulseha/internal/cli"
25+
"github.com/syleron/pulseha/packages/utils"
2526
)
2627

2728
func main() {
@@ -31,17 +32,32 @@ func main() {
3132
}
3233
}
3334

34-
var rootCmd = &cobra.Command{
35-
Use: "pulsectl",
36-
Short: "PulseHA cluster management tool",
37-
Long: `PulseHA cluster management tool - Manage your high availability cluster`,
38-
}
35+
var (
36+
versionFlag bool
37+
rootCmd = &cobra.Command{
38+
Use: "pulsectl",
39+
Short: "PulseHA cluster management tool",
40+
Long: `PulseHA cluster management tool - Manage your high availability cluster`,
41+
Run: func(cmd *cobra.Command, args []string) {
42+
if versionFlag {
43+
fmt.Printf("PulseHA CLI Version: %s\n", utils.Version)
44+
fmt.Printf("Build: %s\n", utils.Build)
45+
os.Exit(0)
46+
}
47+
// If no flags or subcommands, show help
48+
cmd.Help()
49+
},
50+
}
51+
)
3952

4053
func init() {
54+
rootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "Show version information")
55+
4156
rootCmd.AddCommand(
4257
cli.NewClusterCmd(),
4358
cli.NewNodeCmd(),
4459
cli.NewGroupCmd(),
4560
cli.NewStatusCmd(),
61+
cli.NewConfigCmd(), // Add config command
4662
)
4763
}

internal/cli/config.go

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// PulseHA - HA Cluster Daemon
2+
// Copyright (C) 2017-2021 Andrew Zak <andrew@linux.com>
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published
6+
// by the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package cli
18+
19+
import (
20+
"context"
21+
"encoding/json"
22+
"fmt"
23+
"os"
24+
"text/tabwriter"
25+
26+
"github.com/spf13/cobra"
27+
"github.com/syleron/pulseha/internal/client"
28+
"github.com/syleron/pulseha/packages/config"
29+
rpc "github.com/syleron/pulseha/rpc"
30+
)
31+
32+
// NewConfigCmd creates the config command
33+
func NewConfigCmd() *cobra.Command {
34+
cmd := &cobra.Command{
35+
Use: "config",
36+
Short: "Manage configuration settings",
37+
Long: `View and modify PulseHA configuration settings`,
38+
}
39+
40+
cmd.AddCommand(
41+
newConfigGetCmd(),
42+
newConfigSetCmd(),
43+
)
44+
45+
return cmd
46+
}
47+
48+
// newConfigGetCmd creates the config get command
49+
func newConfigGetCmd() *cobra.Command {
50+
return &cobra.Command{
51+
Use: "get [key]",
52+
Short: "Get configuration value(s)",
53+
Long: `Get configuration value(s). If no key is specified, all values are shown.`,
54+
Args: cobra.MaximumNArgs(1),
55+
Run: func(cmd *cobra.Command, args []string) {
56+
// Connect to local server
57+
c, err := client.New()
58+
if err != nil {
59+
fmt.Printf("Error: %v\n", err)
60+
os.Exit(1)
61+
}
62+
defer c.Connection.Close()
63+
64+
// Get local config
65+
cfg := config.New()
66+
67+
if len(args) == 0 {
68+
// Show all config values
69+
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
70+
fmt.Fprintln(w, "Configuration Settings:")
71+
fmt.Fprintln(w, "======================")
72+
fmt.Fprintf(w, "Mode:\t%s\n", cfg.Pulse.Mode)
73+
fmt.Fprintf(w, "Logging Level:\t%s\n", cfg.Pulse.LoggingLevel)
74+
fmt.Fprintf(w, "Log to File:\t%v\n", cfg.Pulse.LogToFile)
75+
fmt.Fprintf(w, "Log to Syslog:\t%v\n", cfg.Pulse.LogToSyslog)
76+
fmt.Fprintf(w, "Health Check Interval:\t%dms\n", cfg.Pulse.HealthCheckInterval)
77+
fmt.Fprintf(w, "Failover Interval:\t%dms\n", cfg.Pulse.FailOverInterval)
78+
fmt.Fprintf(w, "Failover Limit:\t%dms\n", cfg.Pulse.FailOverLimit)
79+
fmt.Fprintf(w, "Auto Failback:\t%v\n", cfg.Pulse.AutoFailback)
80+
fmt.Fprintf(w, "Quorum Enabled:\t%v\n", cfg.Pulse.QuorumEnabled)
81+
fmt.Fprintf(w, "Quorum Min Nodes:\t%d\n", cfg.Pulse.QuorumMinNodes)
82+
w.Flush()
83+
} else {
84+
// Show specific config value
85+
key := args[0]
86+
switch key {
87+
case "mode":
88+
fmt.Println(cfg.Pulse.Mode)
89+
case "logging_level":
90+
fmt.Println(cfg.Pulse.LoggingLevel)
91+
case "log_to_file":
92+
fmt.Println(cfg.Pulse.LogToFile)
93+
case "log_to_syslog":
94+
fmt.Println(cfg.Pulse.LogToSyslog)
95+
case "hcs_interval":
96+
fmt.Println(cfg.Pulse.HealthCheckInterval)
97+
case "fos_interval":
98+
fmt.Println(cfg.Pulse.FailOverInterval)
99+
case "fo_limit":
100+
fmt.Println(cfg.Pulse.FailOverLimit)
101+
case "auto_failback":
102+
fmt.Println(cfg.Pulse.AutoFailback)
103+
case "quorum_enabled":
104+
fmt.Println(cfg.Pulse.QuorumEnabled)
105+
case "quorum_min_nodes":
106+
fmt.Println(cfg.Pulse.QuorumMinNodes)
107+
default:
108+
// Try to get it as JSON field
109+
data, _ := json.Marshal(cfg.Pulse)
110+
var m map[string]interface{}
111+
json.Unmarshal(data, &m)
112+
if val, ok := m[key]; ok {
113+
fmt.Println(val)
114+
} else {
115+
fmt.Printf("Error: unknown config key: %s\n", key)
116+
os.Exit(1)
117+
}
118+
}
119+
}
120+
},
121+
}
122+
}
123+
124+
// newConfigSetCmd creates the config set command
125+
func newConfigSetCmd() *cobra.Command {
126+
return &cobra.Command{
127+
Use: "set <key> <value>",
128+
Short: "Set configuration value",
129+
Long: `Set a configuration value and apply it to the cluster`,
130+
Args: cobra.ExactArgs(2),
131+
Run: func(cmd *cobra.Command, args []string) {
132+
key := args[0]
133+
value := args[1]
134+
135+
// Connect to server
136+
c, err := client.New()
137+
if err != nil {
138+
fmt.Printf("Error: %v\n", err)
139+
os.Exit(1)
140+
}
141+
defer c.Connection.Close()
142+
143+
// Send update request
144+
ctx := context.Background()
145+
resp, err := c.CLI().UpdateConfig(ctx, &rpc.UpdateConfigRequest{
146+
Key: key,
147+
Value: value,
148+
})
149+
if err != nil {
150+
fmt.Printf("Error: %v\n", err)
151+
os.Exit(1)
152+
}
153+
154+
if resp.Success {
155+
fmt.Printf("Successfully updated %s to %s\n", key, value)
156+
} else {
157+
fmt.Printf("Error: %s\n", resp.Message)
158+
os.Exit(1)
159+
}
160+
},
161+
}
162+
}

internal/cli/group.go

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ func NewGroupCmd() *cobra.Command {
2929
}
3030

3131
func newGroupCreateCmd() *cobra.Command {
32-
var name string
33-
3432
cmd := &cobra.Command{
35-
Use: "create",
33+
Use: "create <group-name>",
3634
Short: "Create a new IP group",
35+
Args: cobra.ExactArgs(1),
3736
RunE: func(cmd *cobra.Command, args []string) error {
37+
name := args[0]
38+
3839
client, err := client.New()
3940
if err != nil {
4041
fmt.Printf("Failed to create client: %v\n", err)
@@ -51,9 +52,6 @@ func newGroupCreateCmd() *cobra.Command {
5152
},
5253
}
5354

54-
cmd.Flags().StringVar(&name, "name", "", "Name of the group to create")
55-
cmd.MarkFlagRequired("name")
56-
5755
return cmd
5856
}
5957

@@ -263,15 +261,15 @@ func newGroupUnassignCmd() *cobra.Command {
263261
}
264262

265263
func newGroupDeleteCmd() *cobra.Command {
266-
var (
267-
name string
268-
force bool
269-
)
264+
var force bool
270265

271266
cmd := &cobra.Command{
272-
Use: "delete",
267+
Use: "delete <group-name>",
273268
Short: "Delete an IP group",
269+
Args: cobra.ExactArgs(1),
274270
RunE: func(cmd *cobra.Command, args []string) error {
271+
name := args[0]
272+
275273
client, err := client.New()
276274
if err != nil {
277275
fmt.Printf("Failed to create client: %v\n", err)
@@ -283,13 +281,12 @@ func newGroupDeleteCmd() *cobra.Command {
283281
os.Exit(1)
284282
}
285283

284+
fmt.Printf("Successfully deleted group %s\n", name)
286285
return nil
287286
},
288287
}
289288

290-
cmd.Flags().StringVar(&name, "name", "", "Name of the group to delete")
291289
cmd.Flags().BoolVar(&force, "force", false, "Force deletion even if assigned to nodes")
292-
cmd.MarkFlagRequired("name")
293290

294291
return cmd
295292
}

packages/config/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func New() *Config {
112112
FailOverLimit: 10000,
113113
LoggingLevel: "info",
114114
AutoFailback: true,
115-
LogToFile: true,
115+
LogToFile: false, // Default to syslog only
116116
LogFileLocation: filepath.Join(CONFIG_DIR, "pulseha.log"),
117117
LogToSyslog: true,
118118
SyslogNetwork: "",
@@ -339,7 +339,7 @@ func (c *Config) SaveDefaultLocalConfig() error {
339339
LocalNode: hostname,
340340
ClusterToken: "",
341341
LoggingLevel: "info",
342-
LogToFile: true,
342+
LogToFile: false, // Default to syslog only
343343
LogFileLocation: filepath.Join(CONFIG_DIR, "pulseha.log"),
344344
LogToSyslog: true,
345345
SyslogNetwork: "",

packages/utils/utils.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ import (
2828
"time"
2929
)
3030

31+
// Version information - can be overridden at build time
32+
var (
33+
Version = "development"
34+
Build = "unknown"
35+
)
36+
3137
/**
3238
Load a specific file and return byte code
3339
**/

0 commit comments

Comments
 (0)