Skip to content

Commit b83965b

Browse files
committed
Add restart allocation function
1 parent 013d550 commit b83965b

20 files changed

Lines changed: 772 additions & 19 deletions

Dockerfile

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
FROM golang:1.23.6 as builder
22

3-
COPY . /go/src/github.com/DistroByte/molocule
3+
COPY vendor /go/src/github.com/DistroByte/molecule/vendor
4+
COPY . /go/src/github.com/DistroByte/molecule
45

5-
WORKDIR /go/src/github.com/DistroByte/molocule
6+
WORKDIR /go/src/github.com/DistroByte/molecule
67

7-
RUN CGO_ENABLED=0 go build -o bin/molocule .
8+
RUN CGO_ENABLED=0 go build -o bin/molecule .
89

910
FROM gcr.io/distroless/static-debian12
1011

11-
COPY --from=builder /go/src/github.com/DistroByte/molocule/bin/molocule /bin/molocule
12-
COPY --from=builder /go/src/github.com/DistroByte/molocule/web /web
12+
COPY --from=builder /go/src/github.com/DistroByte/molocule/bin/molecule /bin/molecule
13+
COPY --from=builder /go/src/github.com/DistroByte/molecule/web /web
1314

1415
WORKDIR /
1516

16-
ENTRYPOINT ["/bin/molocule"]
17+
ENTRYPOINT ["/bin/molecule"]

apispec/spec/index.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ paths:
2323
$ref: v1/urls/host-urls.yaml
2424
/v1/urls/traefik:
2525
$ref: v1/urls/traefik-urls.yaml
26+
/v1/services/{service}:
27+
$ref: v1/services/index.yaml
28+
/v1/services/{service}/alloc-restart:
29+
$ref: v1/services/alloc-restart.yaml
30+
security:
31+
- ApiKeyAuth: []
2632

2733
components:
2834
securitySchemes:
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
parameters:
2+
- name: service
3+
in: path
4+
required: true
5+
schema:
6+
$ref: schemas/service-name.json
7+
description: The name of the service
8+
9+
post:
10+
summary: Restart all allocations of a service
11+
operationId: restart_service_allocations
12+
responses:
13+
"200":
14+
description: OK
15+
content:
16+
application/json:
17+
schema:
18+
$ref: schemas/generic-response.json
19+
"400":
20+
description: Invalid request
21+
content:
22+
application/json:
23+
schema:
24+
$ref: schemas/generic-response.json
25+
"500":
26+
description: Internal server error
27+
content:
28+
application/json:
29+
schema:
30+
$ref: schemas/generic-response.json
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
parameters:
2+
- name: service
3+
in: path
4+
required: true
5+
schema:
6+
$ref: schemas/service-name.json
7+
description: The name of the service
8+
9+
get:
10+
summary: Get the status of a service
11+
operationId: get_service_status
12+
responses:
13+
"200":
14+
description: OK
15+
content:
16+
application/json:
17+
schema:
18+
$ref: schemas/service-status.json
19+
"400":
20+
description: Invalid request
21+
content:
22+
application/json:
23+
schema:
24+
$ref: schemas/generic-response.json
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"status": {
5+
"type": "string",
6+
"enum": ["success", "error"]
7+
},
8+
"message": {
9+
"type": "string"
10+
}
11+
}
12+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "string",
3+
"pattern": "^[a-z0-9-]+$",
4+
"example": "molecule"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "string",
3+
"pattern": "^[a-z0-9-]+$",
4+
"example": "running"
5+
}

internal/api/v1/nomad_service.go

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ type NomadServiceInterface interface {
2424
ExtractURLs() (map[string]string, error)
2525
ExtractHostPorts() (map[string]string, error)
2626
ExtractServicePorts() (map[string]string, error)
27+
GetServiceStatus(service string) (map[string]string, error)
28+
RestartServiceAllocations(service string) (map[string]string, error)
2729
}
2830

2931
var (
@@ -42,7 +44,7 @@ func NewNomadService(nomadClient *api.Client) NomadServiceInterface {
4244
standardURLs["photos"] = "https://photos.dbyte.xyz"
4345
standardURLs["drive"] = "https://drive.dbyte.xyz"
4446
standardURLs["plex"] = "https://video.dbyte.xyz"
45-
standardURLs["ghost"] = "https://admin-photo.james-hackett.ie"
47+
standardURLs["ghost"] = "https://admin-photo.james-hackett.ie/ghost"
4648

4749
return &NomadService{nomadClient: nomadClient}
4850
}
@@ -147,6 +149,72 @@ func (s *NomadService) ExtractServicePorts() (map[string]string, error) {
147149
return servicePorts, nil
148150
}
149151

152+
func (s *NomadService) GetServiceStatus(serviceName string) (map[string]string, error) {
153+
allocations, _, err := s.nomadClient.Allocations().List(nil)
154+
if err != nil {
155+
log.Error().Err(err).Msg("Failed to list allocations")
156+
return nil, err
157+
}
158+
159+
serviceUrls = make(map[string]string)
160+
hostReservedPorts = make(map[string]string)
161+
servicePorts = make(map[string]string)
162+
163+
for _, allocation := range allocations {
164+
s.processAllocation(allocation)
165+
}
166+
167+
s.mu.Lock()
168+
defer s.mu.Unlock()
169+
170+
if val, ok := serviceUrls[serviceName]; ok {
171+
return map[string]string{serviceName: val}, nil
172+
}
173+
174+
if val, ok := hostReservedPorts[serviceName]; ok {
175+
return map[string]string{serviceName: val}, nil
176+
}
177+
178+
if val, ok := servicePorts[serviceName]; ok {
179+
return map[string]string{serviceName: val}, nil
180+
}
181+
182+
return nil, nil
183+
}
184+
185+
// when called, this function will restart all allocations for a specific service
186+
// this is useful when a new version of a service is built and you want to restart all instances
187+
func (s *NomadService) RestartServiceAllocations(serviceName string) (map[string]string, error) {
188+
allocations, _, err := s.nomadClient.Allocations().List(nil)
189+
if err != nil {
190+
log.Error().Err(err).Msg("Failed to list allocations")
191+
return nil, err
192+
}
193+
194+
for _, allocation := range allocations {
195+
job, _, err := s.nomadClient.Jobs().Info(allocation.JobID, nil)
196+
if err != nil {
197+
log.Error().Err(err).Msg("Failed to get job info")
198+
return nil, err
199+
}
200+
201+
if *job.Name == serviceName {
202+
allocationInfo, _, err := s.nomadClient.Allocations().Info(allocation.ID, nil)
203+
if err != nil {
204+
log.Error().Err(err).Msg("Failed to get allocation info")
205+
return nil, err
206+
}
207+
err = s.nomadClient.Allocations().Restart(allocationInfo, "", nil)
208+
if err != nil {
209+
log.Error().Err(err).Msg("Failed to restart service allocations")
210+
return nil, err
211+
}
212+
}
213+
}
214+
215+
return nil, nil
216+
}
217+
150218
func (s *NomadService) processAllocation(allocation *api.AllocationListStub) {
151219
services := []*api.Service{}
152220

internal/api/v1/nomad_service_mock.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,13 @@ func (m *MockNomadService) ExtractServicePorts() (map[string]string, error) {
3434
log.Debug().Msg("Mock: ExtractServicePorts called")
3535
return urls, nil
3636
}
37+
38+
func (m *MockNomadService) GetServiceStatus(service string) (map[string]string, error) {
39+
log.Debug().Msg("Mock: GetServiceStatus called")
40+
return urls, nil
41+
}
42+
43+
func (m *MockNomadService) RestartServiceAllocations(service string) (map[string]string, error) {
44+
log.Debug().Msg("Mock: RestartServiceAllocations called")
45+
return urls, nil
46+
}

internal/api/v1/url_service.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,23 @@ func (s *MoleculeAPIService) GetTraefikURLs(ctx context.Context) (openapi.ImplRe
4646
// Return the response
4747
return openapi.Response(http.StatusOK, urls), nil
4848
}
49+
50+
func (s *MoleculeAPIService) GetServiceStatus(ctx context.Context, service string) (openapi.ImplResponse, error) {
51+
status, err := s.nomadService.GetServiceStatus(service)
52+
if err != nil {
53+
return openapi.Response(http.StatusInternalServerError, err.Error()), nil
54+
}
55+
56+
// Return the response
57+
return openapi.Response(http.StatusOK, status), nil
58+
}
59+
60+
func (s *MoleculeAPIService) RestartServiceAllocations(ctx context.Context, service string) (openapi.ImplResponse, error) {
61+
_, err := s.nomadService.RestartServiceAllocations(service)
62+
if err != nil {
63+
return openapi.Response(http.StatusInternalServerError, err.Error()), nil
64+
}
65+
66+
// Return the response
67+
return openapi.Response(http.StatusOK, "OK"), nil
68+
}

0 commit comments

Comments
 (0)