Skip to content

Commit a463467

Browse files
committed
feat(inventory): runner field
1 parent a6c6124 commit a463467

File tree

9 files changed

+124
-62
lines changed

9 files changed

+124
-62
lines changed

api/projects/runners.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,15 @@ func SetRunnerActive(w http.ResponseWriter, r *http.Request) {
5050
func ClearRunnerCache(w http.ResponseWriter, r *http.Request) {
5151
w.WriteHeader(http.StatusNotFound)
5252
}
53+
54+
func GetRunnerTags(w http.ResponseWriter, r *http.Request) {
55+
project := context.Get(r, "project").(db.Project)
56+
tags, err := helpers.Store(r).GetRunnerTags(project.ID)
57+
58+
if err != nil {
59+
w.WriteHeader(http.StatusInternalServerError)
60+
return
61+
}
62+
63+
helpers.WriteJSON(w, http.StatusOK, tags)
64+
}

api/router.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ func Route() *mux.Router {
272272

273273
projectUserAPI.Path("/runners").HandlerFunc(projects.GetRunners).Methods("GET", "HEAD")
274274
projectUserAPI.Path("/runners").HandlerFunc(projects.AddRunner).Methods("POST")
275+
projectUserAPI.Path("/runner_tags").HandlerFunc(projects.GetRunnerTags).Methods("GET", "HEAD")
275276

276277
projectRunnersAPI := projectUserAPI.PathPrefix("/runners").Subrouter()
277278
projectRunnersAPI.Use(projects.RunnerMiddleware)
@@ -566,7 +567,7 @@ func getSystemInfo(w http.ResponseWriter, r *http.Request) {
566567
"auth_methods": authMethods,
567568

568569
"premium_features": map[string]bool{
569-
"project_runners": false,
570+
"project_runners": true,
570571
"terraform_backend": false,
571572
},
572573

db/Store.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ type Store interface {
369369
CreateRunner(runner Runner) (Runner, error)
370370
TouchRunner(runner Runner) (err error)
371371
ClearRunnerCache(runner Runner) (err error)
372-
GetRunnerTags() ([]RunnerTag, error)
372+
GetRunnerTags(projectID int) ([]RunnerTag, error)
373373

374374
GetTemplateVaults(projectID int, templateID int) ([]TemplateVault, error)
375375
CreateTemplateVault(vault TemplateVault) (TemplateVault, error)
@@ -621,6 +621,32 @@ func ValidateInventory(store Store, inventory *Inventory) (err error) {
621621
return
622622
}
623623

624+
type StringArrayField []string
625+
626+
func (m *StringArrayField) Scan(value any) error {
627+
if value == nil {
628+
*m = nil
629+
return nil
630+
}
631+
632+
switch v := value.(type) {
633+
case []byte:
634+
return json.Unmarshal(v, m)
635+
case string:
636+
return json.Unmarshal([]byte(v), m)
637+
default:
638+
return errors.New("unsupported type for MapStringAnyField")
639+
}
640+
}
641+
642+
// Value implements the driver.Valuer interface for MapStringAnyField
643+
func (m *StringArrayField) Value() (driver.Value, error) {
644+
if m == nil {
645+
return nil, nil
646+
}
647+
return json.Marshal(m)
648+
}
649+
624650
type MapStringAnyField map[string]any
625651

626652
func (m *MapStringAnyField) Scan(value any) error {
@@ -640,7 +666,7 @@ func (m *MapStringAnyField) Scan(value any) error {
640666
}
641667

642668
// Value implements the driver.Valuer interface for MapStringAnyField
643-
func (m MapStringAnyField) Value() (driver.Value, error) {
669+
func (m *MapStringAnyField) Value() (driver.Value, error) {
644670
if m == nil {
645671
return nil, nil
646672
}

db/bolt/runner.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ func (d *BoltDb) DeleteRunner(projectID int, runnerID int) (err error) {
2121
return
2222
}
2323

24-
func (d *BoltDb) GetRunnerTags() ([]db.RunnerTag, error) {
25-
return nil, nil
24+
func (d *BoltDb) GetRunnerTags(projectID int) ([]db.RunnerTag, error) {
25+
return []db.RunnerTag{
26+
{
27+
Tag: "tag1",
28+
NumberOfRunners: 1,
29+
},
30+
}, nil
2631
}

db/sql/runner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ func (d *SqlDb) DeleteRunner(projectID int, runnerID int) (err error) {
2121
return
2222
}
2323

24-
func (d *SqlDb) GetRunnerTags() ([]db.RunnerTag, error) {
25-
return nil, nil
24+
func (d *SqlDb) GetRunnerTags(projectID int) ([]db.RunnerTag, error) {
25+
return []db.RunnerTag{}, nil
2626
}

web/src/components/InventoryForm.vue

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
11
<template>
2+
<v-skeleton-loader
3+
v-if="!isLoaded"
4+
type="
5+
table-heading,
6+
image,
7+
list-item-two-line,
8+
list-item-two-line,
9+
list-item-two-line,
10+
list-item-two-line,
11+
list-item-two-line,
12+
list-item-two-line,
13+
list-item-two-line,
14+
list-item-two-line"
15+
></v-skeleton-loader>
216
<v-form
17+
v-else
318
ref="form"
419
lazy-validation
520
v-model="formValid"
6-
v-if="item != null && keys != null"
721
>
822
<v-alert
923
:value="formError"
@@ -18,8 +32,23 @@
1832
:rules="[v => !!v || $t('name_required')]"
1933
required
2034
:disabled="formSaving"
35+
outlined
36+
dense
2137
></v-text-field>
2238

39+
<v-autocomplete
40+
v-if="premiumFeatures.project_runners"
41+
v-model="item.runner_tag"
42+
:items="runnerTags"
43+
:label="$t('runner_tag')"
44+
item-value="tag"
45+
item-text="tag"
46+
outlined
47+
dense
48+
:disabled="formSaving"
49+
:placeholder="$t('runner_tag')"
50+
></v-autocomplete>
51+
2352
<v-select
2453
v-model="item.ssh_key_id"
2554
:label="$t('userCredentials')"
@@ -29,6 +58,8 @@
2958
:rules="[v => !!v || $t('user_credentials_required')]"
3059
required
3160
:disabled="formSaving"
61+
outlined
62+
dense
3263
></v-select>
3364

3465
<v-select
@@ -39,6 +70,8 @@
3970
item-value="id"
4071
item-text="name"
4172
:disabled="formSaving"
73+
outlined
74+
dense
4275
></v-select>
4376

4477
<v-select
@@ -50,6 +83,8 @@
5083
item-text="name"
5184
required
5285
:disabled="formSaving"
86+
outlined
87+
dense
5388
></v-select>
5489

5590
<v-text-field
@@ -59,6 +94,8 @@
5994
required
6095
:disabled="formSaving"
6196
v-if="item.type === 'file'"
97+
outlined
98+
dense
6299
></v-text-field>
63100

64101
<v-select
@@ -70,6 +107,8 @@
70107
item-text="name"
71108
:disabled="formSaving"
72109
v-if="item.type === 'file'"
110+
outlined
111+
dense
73112
></v-select>
74113

75114
<codemirror
@@ -85,42 +124,6 @@
85124
:placeholder="$t('enterInventory')"
86125
/>
87126

88-
<v-text-field
89-
v-model="item.runner_tag"
90-
:label="$t('runner_tag')"
91-
:rules="[v => !!v || $t('name_required')]"
92-
required
93-
:disabled="formSaving"
94-
></v-text-field>
95-
96-
<v-alert
97-
dense
98-
text
99-
class="mt-4"
100-
type="info"
101-
v-if="item.type === 'static'"
102-
>
103-
{{ $t('staticInventoryExample') }}
104-
<pre style="font-size: 14px;">[website]
105-
172.18.8.40
106-
172.18.8.41</pre>
107-
</v-alert>
108-
109-
<v-alert
110-
dense
111-
text
112-
class="mt-4"
113-
type="info"
114-
v-if="item.type === 'static-yaml'"
115-
>
116-
{{ $t('staticYamlInventoryExample') }}
117-
<pre style="font-size: 14px;">all:
118-
children:
119-
website:
120-
hosts:
121-
172.18.8.40:
122-
172.18.8.41:</pre>
123-
</v-alert>
124127
</v-form>
125128
</template>
126129
<style>
@@ -140,7 +143,6 @@
140143
/* eslint-disable import/no-extraneous-dependencies,import/extensions */
141144
142145
import ItemFormBase from '@/components/ItemFormBase';
143-
import axios from 'axios';
144146
145147
import { codemirror } from 'vue-codemirror';
146148
import 'codemirror/lib/codemirror.css';
@@ -154,6 +156,10 @@ export default {
154156
codemirror,
155157
},
156158
159+
props: {
160+
premiumFeatures: Object,
161+
},
162+
157163
data() {
158164
return {
159165
cmOptions: {
@@ -188,6 +194,7 @@ export default {
188194
}],
189195
keys: null,
190196
repositories: null,
197+
runnerTags: null,
191198
};
192199
},
193200
@@ -198,21 +205,21 @@ export default {
198205
}
199206
return this.keys.filter((key) => key.type === 'login_password');
200207
},
208+
isLoaded() {
209+
return this.item != null && this.keys != null;
210+
},
201211
},
202212
203213
async created() {
204-
[this.keys, this.repositories] = (await Promise.all([
205-
await axios({
206-
keys: 'get',
207-
url: `/api/project/${this.projectId}/keys`,
208-
responseType: 'json',
209-
}),
210-
await axios({
211-
keys: 'get',
212-
url: `/api/project/${this.projectId}/repositories`,
213-
responseType: 'json',
214-
}),
215-
])).map((x) => x.data);
214+
[
215+
this.keys,
216+
this.repositories,
217+
this.runnerTags,
218+
] = await Promise.all([
219+
this.loadProjectResources('keys'),
220+
this.loadProjectResources('repositories'),
221+
this.loadProjectResources('runner_tags'),
222+
]);
216223
},
217224
218225
methods: {

web/src/components/TemplateForm.vue

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,18 @@
246246
:placeholder="$t('branch')"
247247
></v-text-field>
248248

249-
<v-text-field
249+
<v-autocomplete
250250
v-if="premiumFeatures.project_runners"
251251
v-model="item.runner_tag"
252+
:items="runnerTags"
252253
:label="fieldLabel('runner_tag')"
254+
item-value="tag"
255+
item-text="tag"
253256
outlined
254257
dense
255258
:disabled="formSaving"
256259
:placeholder="$t('runner_tag')"
257-
></v-text-field>
260+
></v-autocomplete>
258261

259262
<SurveyVars
260263
:vars="surveyVars"
@@ -528,6 +531,7 @@ export default {
528531
helpKey: null,
529532
530533
args: [],
534+
runnerTags: null,
531535
};
532536
},
533537
@@ -618,7 +622,8 @@ export default {
618622
&& this.environment != null
619623
&& this.item != null
620624
&& this.schedules != null
621-
&& this.views != null;
625+
&& this.views != null
626+
&& this.runnerTags != null;
622627
},
623628
624629
},
@@ -684,6 +689,7 @@ export default {
684689
this.views,
685690
this.environment,
686691
templates,
692+
this.runnerTags,
687693
] = await Promise.all([
688694
this.loadProjectResources('repositories'),
689695
this.loadProjectEndpoint(`/inventory?app=${this.app}&template_id=${this.itemId}`),
@@ -692,6 +698,7 @@ export default {
692698
this.loadProjectResources('views'),
693699
this.loadProjectResources('environment'),
694700
this.loadProjectResources('templates'),
701+
this.loadProjectResources('runner_tags'),
695702
]);
696703
697704
this.inventory = [...inventory1, ...inventory2];

web/src/views/Auth.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,14 @@
7373
justify-center
7474
class="pa-0"
7575
>
76-
<v-card class="px-5 py-5" style="margin-bottom: 10%; border-radius: 15px;">
76+
<v-card class="px-5 py-5" style="border-radius: 15px;">
7777
<v-card-text>
7878
<v-form
7979
ref="signInForm"
8080
lazy-validation
8181
v-model="signInFormValid"
8282
style="width: 350px;"
8383
>
84-
8584
<v-img
8685
width="80"
8786
height="80"

web/src/views/project/Inventory.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
@error="onError"
4040
:need-save="needSave"
4141
:need-reset="needReset"
42+
:premium-features="premiumFeatures"
4243
/>
4344
</template>
4445
</EditDialog>
@@ -163,6 +164,10 @@ export default {
163164
mixins: [ItemListPageBase, AppsMixin],
164165
components: { TemplateSelectForm, InventoryForm },
165166
167+
props: {
168+
premiumFeatures: Object,
169+
},
170+
166171
data() {
167172
return {
168173
apps: ['ansible'],

0 commit comments

Comments
 (0)