Skip to content

Commit

Permalink
Merge pull request #23 from ggiamarchi/reboot-now
Browse files Browse the repository at this point in the history
Reboot now
  • Loading branch information
ggiamarchi authored Mar 30, 2020
2 parents 1f5b627 + 249b6fb commit bedbe92
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 31 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,26 @@ Code | Name | Description
-------|-------------|---------------------------------------------------
`20O` | `Ok` | Server configurations have been retrieved

## Show configurations

```
GET /v1/configurations/<name>
```

###### Response

```json
{
"name": "local",
"content": "default local\n\nlabel local\n localboot 0\n"
}
```

###### Response codes

Code | Name | Description
-------|-------------|---------------------------------------------------
`20O` | `Ok` | Configuration detail have been retrieved

## Read hosts

Expand Down Expand Up @@ -291,6 +311,7 @@ Attribute | Type | Required | Description
---------------|----------|----------|---------------------------------------------
`name` | string | No | Host name
`mac_address` | string | No | Host MAC address
`reboot` | bool | No | Whether the host should be rebooted automatically or not


###### Response codes
Expand Down
4 changes: 2 additions & 2 deletions api/configurations.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func deployConfiguration(api *gin.RouterGroup, appConfig *model.AppConfig) {
return
}

err := service.DeployConfiguration(appConfig, c.Param("name"), hosts.Hosts)
resp, err := service.DeployConfiguration(appConfig, c.Param("name"), hosts.Hosts)
if err != nil {
switch v := err.(type) {
case *service.PXEError:
Expand All @@ -54,7 +54,7 @@ func deployConfiguration(api *gin.RouterGroup, appConfig *model.AppConfig) {
}
return
}
c.Writer.WriteHeader(200)
c.JSON(200, resp)
})
}

Expand Down
25 changes: 10 additions & 15 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,6 @@ func setupCLI() {
}

fmt.Println(configuration.Content)
// Print data table
// table := tablewriter.NewWriter(os.Stdout)
// table.SetAutoWrapText(false)
// table.SetHeader([]string{"Name", "Content"})
// table.Append([]string{configuration.Name, configuration.Content})
// table.Render()
}
})
cmd.Command("list", "List available PXE configurations", func(cmd *cli.Cmd) {
Expand All @@ -78,9 +72,11 @@ func setupCLI() {
})
cmd.Command("deploy", "Deploy a configuration for a host", func(cmd *cli.Cmd) {

cmd.Spec = "CONFIG HOSTNAMES..."
cmd.Spec = "[-n] CONFIG HOSTNAMES..."

var (
now = cmd.BoolOpt("n now", false, "Trigger a server reboot when the configuration is set")

config = cmd.StringArg("CONFIG", "", "Configuration to deploy")
hostnames = cmd.StringsArg("HOSTNAMES", []string{}, "Hosts for whom to deploy a configuration")
)
Expand All @@ -93,32 +89,31 @@ func setupCLI() {

for i, h := range *hostnames {
hosts[i] = &model.HostQuery{
Name: h,
Name: h,
Reboot: *now,
}
}

hostsQuery := &model.HostsQuery{
Hosts: hosts,
}

resp := &struct {
Message string
}{}
resp := &model.HostsResponse{}

statusCode, err := http.Request("PUT", *serverURL, "/v1/configurations/"+*config+"/deploy", hostsQuery, resp)

if err != nil || statusCode != 200 {
os.Stdout.WriteString(resp.Message + "\n")
cli.Exit(1)
}

// Print data table
table := tablewriter.NewWriter(os.Stdout)
table.SetAutoWrapText(false)
table.SetHeader([]string{"Name", "Configuration"})
table.SetHeader([]string{"Name", "Configuration", "Rebooted"})

for _, h := range *hostnames {
table.Append([]string{h, *config})
for _, h := range resp.Hosts {
table.Append([]string{h.Name, *config, h.Rebooted})
fmt.Println(5)
}

table.Render()
Expand Down
19 changes: 19 additions & 0 deletions model/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type HostQuery struct {
Name string `json:"name"`
MACAddress string `json:"macAddress"`
Configuration string `json:"configuration"`
Reboot bool `json:"reboot"`
}

func (h *HostQuery) String() string {
Expand All @@ -30,3 +31,21 @@ type HostsQuery struct {
func (h *HostsQuery) String() string {
return fmt.Sprintf("%+v", *h)
}

type HostResponse struct {
Name string `json:"name"`
Configuration string `json:"configuration"`
Rebooted string `json:"rebooted"`
}

func (h *HostResponse) String() string {
return fmt.Sprintf("%+v", *h)
}

type HostsResponse struct {
Hosts []*HostResponse `json:"hosts"`
}

func (h *HostsResponse) String() string {
return fmt.Sprintf("%+v", *h)
}
52 changes: 38 additions & 14 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func ReadConfigurationContent(appConfig *model.AppConfig, name string) (*model.C
return c, nil
}

func DeployConfiguration(appConfig *model.AppConfig, name string, hosts []*model.HostQuery) error {
func DeployConfiguration(appConfig *model.AppConfig, name string, hosts []*model.HostQuery) (*model.HostsResponse, error) {
logger.Info("Deploy configuration :: %s :: %+v", name, hosts)

configExists := false
Expand All @@ -194,7 +194,7 @@ func DeployConfiguration(appConfig *model.AppConfig, name string, hosts []*model
}
}
if !configExists {
return newPXEError("NOT_FOUND", "Configuration '%s' does not exists", name)
return nil, newPXEError("NOT_FOUND", "Configuration '%s' does not exists", name)
}

// Build maps in oder to optimize further searches
Expand All @@ -218,31 +218,31 @@ func DeployConfiguration(appConfig *model.AppConfig, name string, hosts []*model
logger.Info("Processing :: %+v", qh)

if qh.Configuration != "" {
return newPXEError("CONFILCT", "Configuration attribute for a host in this context is not allowed")
return nil, newPXEError("CONFILCT", "Configuration attribute for a host in this context is not allowed")
}

if qh.Name != "" {
if hostsByName[qh.Name] == nil {
return newPXEError("NOT_FOUND", "No host declared for name <%s>", qh.Name)
return nil, newPXEError("NOT_FOUND", "No host declared for name <%s>", qh.Name)
}
if qh.MACAddress != "" {
if hostsByMAC[qh.MACAddress] != nil {
host := hostsByMAC[qh.MACAddress]
if host.Name != qh.Name {
return newPXEError("CONFLICT", "Host <%s> does not match MAC address <%s>", qh.Name, qh.MACAddress)
return nil, newPXEError("CONFLICT", "Host <%s> does not match MAC address <%s>", qh.Name, qh.MACAddress)
}
if hostsToDeploy[host.Name] != nil {
return newPXEError("CONFLICT", "Host <%s> appears several times in query", host.Name)
return nil, newPXEError("CONFLICT", "Host <%s> appears several times in query", host.Name)
}
hostsToDeploy[host.Name] = host

continue
}
return newPXEError("CONFLICT", "MAC address <%s> does not match host <%s>", qh.MACAddress, qh.Name)
return nil, newPXEError("CONFLICT", "MAC address <%s> does not match host <%s>", qh.MACAddress, qh.Name)
}

if hostsToDeploy[qh.Name] != nil {
return newPXEError("CONFLICT", "Host <%s> appears several times in query", qh.Name)
return nil, newPXEError("CONFLICT", "Host <%s> appears several times in query", qh.Name)
}
hostsToDeploy[qh.Name] = hostsByName[qh.Name]

Expand All @@ -251,19 +251,19 @@ func DeployConfiguration(appConfig *model.AppConfig, name string, hosts []*model

if qh.MACAddress != "" {
if hostsByMAC[qh.MACAddress] == nil {
return newPXEError("NOT_FOUND", "No host declared with MAC address <%s>", qh.MACAddress)
return nil, newPXEError("NOT_FOUND", "No host declared with MAC address <%s>", qh.MACAddress)
}

host := hostsByMAC[qh.MACAddress]
if hostsToDeploy[host.Name] != nil {
return newPXEError("CONFLICT", "Host <%s> appears several times in query", host.Name)
return nil, newPXEError("CONFLICT", "Host <%s> appears several times in query", host.Name)
}
hostsToDeploy[host.Name] = host

continue
}

return newPXEError("BAD_REQUEST", "Either Name or MACAddress must be provided for each Host")
return nil, newPXEError("BAD_REQUEST", "Either Name or MACAddress must be provided for each Host")
}

logger.Info("Host to deploy with configuration <%s> :: %+v", name, hostsToDeploy)
Expand All @@ -284,16 +284,40 @@ func DeployConfiguration(appConfig *model.AppConfig, name string, hosts []*model
logger.Info("Creating symlink %s -> %s", srcConfigPath, pxeFilePath)
err := os.Symlink(srcConfigPath, pxeFilePath)
if err != nil {
return newPXEError("TECHNICAL", "Unable to create symlink")
return nil, newPXEError("TECHNICAL", "Unable to create symlink")
}

for i := 1; i < len(h.MACAddresses); i++ {
err := os.Symlink(pxeFilePath, fmt.Sprintf("%s/pxelinux.cfg/%s", appConfig.Tftp.Root, utils.PXEFilenameFromMAC(h.MACAddresses[i])))
if err != nil {
return newPXEError("TECHNICAL", "Unable to create symlink")
return nil, newPXEError("TECHNICAL", "Unable to create symlink")
}
}
}

return nil
hostsResponse := make([]*model.HostResponse, 0)

resp := &model.HostsResponse{
Hosts: hostsResponse,
}

for _, h := range hosts {
hostResponse := &model.HostResponse{
Name: h.Name,
Configuration: h.Configuration,
}
if h.Reboot {
err := RebootHost(hostsByName[h.Name])
if err != nil {
hostResponse.Rebooted = "ERROR"
} else {
hostResponse.Rebooted = "YES"
}
} else {
hostResponse.Rebooted = "NO"
}
resp.Hosts = append(resp.Hosts, hostResponse)
}

return resp, nil
}

0 comments on commit bedbe92

Please sign in to comment.