Skip to content

Commit

Permalink
Possibility to use this tool from command line + fix the wrong defaul…
Browse files Browse the repository at this point in the history
…t path to the configuration file
  • Loading branch information
tr4cks committed Nov 30, 2023
1 parent e765e05 commit 0a2bee2
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 10 deletions.
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ power -m wol --config config.yaml
```

Currently, two modules are available:
* `ilo`: use of HP iLO technology integrated into ProLiant range servers. This module enables the server to be switched on and off with a complete display of its status.
* `wol`: use Wake-on-LAN to start the server. This module only allows the server to be started, and has a restricted display of the server status.
* `ilo`: use of HP iLO technology integrated into ProLiant range servers. This module enables the server to be switched on and off with a complete display of its status.
* `wol`: use Wake-on-LAN to start the server. This module only allows the server to be started, and has a restricted display of
the server status.

*❗️ The `ilo` module has only been implemented and tested based on the `iLO4` API, and is therefore probably not compatible with other major versions. Don't hesitate to start an issue or a pull request if you're interested in other versions.*

Expand Down Expand Up @@ -205,7 +206,7 @@ Finally, all you have to do now is open your browser, type in the address corres



<!-- USAGE EXAMPLES -->
<!-- USAGE -->
## Usage

<div align="center">
Expand All @@ -226,6 +227,29 @@ sudo journalctl -u power@my_module.service

*❕ As the page is not reactive, it must be reloaded to update and view the current server state.*

---

It is also possible to use this tool from the command line. There's no point in instantiating it as a daemon if you only want to use it that way.

Three commands are available:
* `up`: starts the server
* `down`: turns off the server
* `state`: provides server status in JSON format

Since the `ilo` module simulates the pressing of the power button, regardless of whether it is to switch the server on or off, it is advisable to check the status of the server before carrying out such an operation.

For example, if you want to create an entry in your `crontab` to start the server while checking that it's not already running, you can use the following command:

```crontab
SHELL=/bin/bash
0 20 * * * [ "$(power -m ilo state | jq -r '.power == false and .led == false')" = "true" ] && power -m ilo up
```

*❕ The previous command requires the `jq` utility to run.*

Concerning the `wol` module, as mentioned earlier, it does not allow you to shut down the server, so the `down` command will have no effect.

<p align="right">(<a href="#readme-top">back to top</a>)</p>


Expand Down
87 changes: 80 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"embed"
"encoding/json"
"fmt"
"html/template"
"io/fs"
Expand All @@ -22,9 +23,9 @@ import (
)

func init() {
rootCmd.Flags().StringVar(&configFilePath, "config", path.Join("/opt", appName, "config.yaml"), "YAML configuration file")
rootCmd.Flags().StringVarP(&moduleName, "module", "m", "", "module for switching the server on or off")
rootCmd.MarkFlagRequired("module")
rootCmd.PersistentFlags().StringVar(&configFilePath, "config", path.Join("/etc", fmt.Sprintf("%s.d", appName), "config.yaml"), "YAML configuration file")
rootCmd.PersistentFlags().StringVarP(&moduleName, "module", "m", "", "module for switching the server on or off")
rootCmd.MarkPersistentFlagRequired("module")
}

const appName = "power"
Expand All @@ -35,7 +36,7 @@ var (
rootCmd = &cobra.Command{
Use: appName,
Short: "All-in-one tool for remote server power control",
Version: "1.0.0",
Version: "1.1.0",
Args: cobra.NoArgs,
Run: run,
CompletionOptions: cobra.CompletionOptions{
Expand Down Expand Up @@ -65,7 +66,7 @@ func parseYAMLFile(filePath string) (*Config, error) {
return &config, nil
}

func run(cmd *cobra.Command, args []string) {
func parseConfigFile(filePath string) *Config {
config, err := parseYAMLFile(configFilePath)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to parse YAML file %q: %s\n", configFilePath, err)
Expand All @@ -79,6 +80,10 @@ func run(cmd *cobra.Command, args []string) {
os.Exit(1)
}

return config
}

func createModule(config *Config, moduleName string) modules.Module {
internalModules := map[string]modules.Module{
"ilo": ilo.New(),
"wol": wakeonlan.New(),
Expand All @@ -94,13 +99,19 @@ func run(cmd *cobra.Command, args []string) {
os.Exit(1)
}

err = module.Init(config.Module)
err := module.Init(config.Module)
if err != nil {
fmt.Fprintf(os.Stderr, "Error during module initialization: %s\n", err)
os.Exit(1)
return
}

return module
}

func run(cmd *cobra.Command, args []string) {
config := parseConfigFile(configFilePath)
module := createModule(config, moduleName)

runServer(config, module)
}

Expand Down Expand Up @@ -173,6 +184,68 @@ func runServer(config *Config, module modules.Module) {
router.Run()
}

func init() {
rootCmd.AddCommand(upCmd, downCmd, stateCmd)
}

var (
upCmd = &cobra.Command{
Use: "up",
Short: "Start the server",
Run: func(cmd *cobra.Command, args []string) {
config := parseConfigFile(configFilePath)
module := createModule(config, moduleName)

module.PowerOn()
},
}
downCmd = &cobra.Command{
Use: "down",
Short: "Turn off the server",
Run: func(cmd *cobra.Command, args []string) {
config := parseConfigFile(configFilePath)
module := createModule(config, moduleName)

module.PowerOff()
},
}
stateCmd = &cobra.Command{
Use: "state",
Short: "Fetch the server state",
Run: func(cmd *cobra.Command, args []string) {
config := parseConfigFile(configFilePath)
module := createModule(config, moduleName)

powerState, ledState := module.State()

if powerState.Err != nil {
fmt.Fprintf(os.Stderr, "Failed to retrieve POWER state: %s\n", powerState.Err)
os.Exit(1)
}
if ledState.Err != nil {
fmt.Fprintf(os.Stderr, "Failed to retrieve LED state: %s\n", powerState.Err)
os.Exit(1)
}

state := struct {
Power bool `json:"power"`
Led bool `json:"led"`
}{
Power: powerState.Value,
Led: ledState.Value,
}

jsonString, err := json.Marshal(state)
if err != nil {
fmt.Println("Error during JSON conversion:", err)
os.Exit(1)
}

fmt.Println(string(jsonString))
},
}
)

func main() {
err := rootCmd.Execute()
if err != nil {
Expand Down

0 comments on commit 0a2bee2

Please sign in to comment.