Skip to content

Commit 5925c2f

Browse files
johnaoharabarreiro
authored andcommitted
Strongly typed Datastore configuration - Fixes #2088
- Updates from review - Update datastore config checks touse isBlank() - Update docs
1 parent f510a25 commit 5925c2f

File tree

24 files changed

+909
-509
lines changed

24 files changed

+909
-509
lines changed

docs/site/content/en/docs/Integrations/elasticsearch/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ New Datastore
2626
1. Select `Elasticsearch` from the `Datastore Type` dropdown
2727
2. Provide a `Name` for the Datastore
2828
3. Enter the `URL` for the Elasticsearch instance
29-
4. Enter the `API Key` for the Elasticsearch instance, generated in step 1
30-
5. Click `Save`
29+
4. Select `api-key` from `Authentication Type` from dropdown
30+
5. Enter the `API Key` for the Elasticsearch instance, generated in step 1
31+
6. Click `Save`
3132

3233
## Test Configuration
3334

Loading

docs/site/content/en/openapi/openapi.yaml

Lines changed: 102 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ paths:
6666
schema:
6767
format: int32
6868
type: integer
69+
/api/config/datastore/types:
70+
get:
71+
tags:
72+
- Config
73+
description: Obtain list of available datastore types
74+
operationId: datastoreTypes
75+
responses:
76+
"200":
77+
description: OK
78+
content:
79+
application/json:
80+
schema:
81+
type: array
82+
items:
83+
$ref: "#/components/schemas/TypeConfig"
6984
/api/config/datastore/{id}:
7085
delete:
7186
tags:
@@ -77,7 +92,8 @@ paths:
7792
in: path
7893
required: true
7994
schema:
80-
type: string
95+
format: int32
96+
type: integer
8197
responses:
8298
"204":
8399
description: No Content
@@ -92,7 +108,8 @@ paths:
92108
in: path
93109
required: true
94110
schema:
95-
type: string
111+
format: int32
112+
type: integer
96113
responses:
97114
"200":
98115
description: OK
@@ -2569,6 +2586,15 @@ paths:
25692586
description: No Content
25702587
components:
25712588
schemas:
2589+
APIKeyAuth:
2590+
type: object
2591+
properties:
2592+
type:
2593+
description: type
2594+
type: string
2595+
apiKey:
2596+
description: Api key
2597+
type: string
25722598
Access:
25732599
description: "Resources have different visibility within the UI. 'PUBLIC', 'PROTECTED'\
25742600
\ and 'PRIVATE'. Restricted resources are not visible to users who do not\
@@ -2710,17 +2736,26 @@ components:
27102736
CollectorApiDatastoreConfig:
27112737
description: Type of backend datastore
27122738
required:
2739+
- authentication
27132740
- builtIn
2714-
- apiKey
27152741
- url
27162742
type: object
27172743
properties:
2744+
authentication:
2745+
type: object
2746+
oneOf:
2747+
- $ref: "#/components/schemas/NoAuth"
2748+
- $ref: "#/components/schemas/APIKeyAuth"
2749+
- $ref: "#/components/schemas/UsernamePassAuth"
2750+
discriminator:
2751+
propertyName: type
2752+
mapping:
2753+
none: "#/components/schemas/NoAuth"
2754+
api-key: "#/components/schemas/APIKeyAuth"
2755+
username: "#/components/schemas/UsernamePassAuth"
27182756
builtIn:
27192757
description: Built In
27202758
type: boolean
2721-
apiKey:
2722-
description: Collector API KEY
2723-
type: string
27242759
url:
27252760
description: "Collector url, e.g. https://collector.foci.life/api/v1/image-stats"
27262761
type: string
@@ -2992,13 +3027,12 @@ components:
29923027
items:
29933028
$ref: "#/components/schemas/ValidationError"
29943029
Datastore:
2995-
description: Type of backend datastore
3030+
description: Instance of backend datastore
29963031
required:
29973032
- access
29983033
- owner
29993034
- id
30003035
- name
3001-
- builtIn
30023036
- config
30033037
- type
30043038
type: object
@@ -3029,14 +3063,10 @@ components:
30293063
\ Test definition"
30303064
type: string
30313065
example: Perf Elasticsearch
3032-
builtIn:
3033-
description: Is this a built-in datastore? Built-in datastores cannot be
3034-
deleted or modified
3035-
type: boolean
3036-
example: false
30373066
config:
30383067
type: object
30393068
oneOf:
3069+
- $ref: "#/components/schemas/CollectorApiDatastoreConfig"
30403070
- $ref: "#/components/schemas/ElasticsearchDatastoreConfig"
30413071
- $ref: "#/components/schemas/PostgresDatastoreConfig"
30423072
type:
@@ -3078,25 +3108,29 @@ components:
30783108
ElasticsearchDatastoreConfig:
30793109
description: Type of backend datastore
30803110
required:
3111+
- authentication
30813112
- builtIn
30823113
- url
30833114
type: object
30843115
properties:
3116+
authentication:
3117+
type: object
3118+
oneOf:
3119+
- $ref: "#/components/schemas/NoAuth"
3120+
- $ref: "#/components/schemas/APIKeyAuth"
3121+
- $ref: "#/components/schemas/UsernamePassAuth"
3122+
discriminator:
3123+
propertyName: type
3124+
mapping:
3125+
none: "#/components/schemas/NoAuth"
3126+
api-key: "#/components/schemas/APIKeyAuth"
3127+
username: "#/components/schemas/UsernamePassAuth"
30853128
builtIn:
30863129
description: Built In
30873130
type: boolean
3088-
apiKey:
3089-
description: Elasticsearch API KEY
3090-
type: string
30913131
url:
30923132
description: Elasticsearch url
30933133
type: string
3094-
username:
3095-
description: Elasticsearch username
3096-
type: string
3097-
password:
3098-
description: Elasticsearch password
3099-
type: string
31003134
ErrorDetails:
31013135
required:
31023136
- type
@@ -3675,6 +3709,12 @@ components:
36753709
testId:
36763710
format: int32
36773711
type: integer
3712+
NoAuth:
3713+
type: object
3714+
properties:
3715+
type:
3716+
description: type
3717+
type: string
36783718
PersistentLog:
36793719
description: Persistent Log
36803720
required:
@@ -3699,9 +3739,22 @@ components:
36993739
PostgresDatastoreConfig:
37003740
description: Built in backend datastore
37013741
required:
3742+
- authentication
37023743
- builtIn
37033744
type: object
37043745
properties:
3746+
authentication:
3747+
type: object
3748+
oneOf:
3749+
- $ref: "#/components/schemas/NoAuth"
3750+
- $ref: "#/components/schemas/APIKeyAuth"
3751+
- $ref: "#/components/schemas/UsernamePassAuth"
3752+
discriminator:
3753+
propertyName: type
3754+
mapping:
3755+
none: "#/components/schemas/NoAuth"
3756+
api-key: "#/components/schemas/APIKeyAuth"
3757+
username: "#/components/schemas/UsernamePassAuth"
37053758
builtIn:
37063759
description: Built In
37073760
type: boolean
@@ -4883,6 +4936,21 @@ components:
48834936
description: Transformer name
48844937
type: string
48854938
example: my-dataset-transformer
4939+
TypeConfig:
4940+
type: object
4941+
properties:
4942+
enumName:
4943+
type: string
4944+
name:
4945+
type: string
4946+
label:
4947+
type: string
4948+
supportedAuths:
4949+
type: array
4950+
items:
4951+
type: string
4952+
builtIn:
4953+
type: boolean
48864954
UserData:
48874955
required:
48884956
- id
@@ -4899,6 +4967,18 @@ components:
48994967
type: string
49004968
email:
49014969
type: string
4970+
UsernamePassAuth:
4971+
type: object
4972+
properties:
4973+
type:
4974+
description: type
4975+
type: string
4976+
username:
4977+
description: Username
4978+
type: string
4979+
password:
4980+
description: Password
4981+
type: string
49024982
ValidationError:
49034983
required:
49044984
- schemaId
Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,51 @@
11
package io.hyperfoil.tools.horreum.api.data.datastore;
22

3+
import jakarta.validation.constraints.NotNull;
4+
35
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
6+
import org.eclipse.microprofile.openapi.annotations.media.DiscriminatorMapping;
47
import org.eclipse.microprofile.openapi.annotations.media.Schema;
58

9+
import com.fasterxml.jackson.annotation.JsonProperty;
10+
import com.fasterxml.jackson.annotation.JsonSubTypes;
11+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
12+
13+
import io.hyperfoil.tools.horreum.api.data.datastore.auth.APIKeyAuth;
14+
import io.hyperfoil.tools.horreum.api.data.datastore.auth.NoAuth;
15+
import io.hyperfoil.tools.horreum.api.data.datastore.auth.UsernamePassAuth;
16+
617
public abstract class BaseDatastoreConfig {
718

8-
@Schema(type = SchemaType.BOOLEAN, required = true, description = "Built In")
9-
public Boolean builtIn = true;
19+
@NotNull
20+
@JsonProperty(required = true)
21+
@Schema(type = SchemaType.OBJECT, discriminatorProperty = "type", discriminatorMapping = {
22+
@DiscriminatorMapping(schema = NoAuth.class, value = NoAuth._TYPE),
23+
@DiscriminatorMapping(schema = APIKeyAuth.class, value = APIKeyAuth._TYPE),
24+
@DiscriminatorMapping(schema = UsernamePassAuth.class, value = UsernamePassAuth._TYPE)
25+
}, oneOf = { //subtype mapping for openapi
26+
NoAuth.class,
27+
APIKeyAuth.class,
28+
UsernamePassAuth.class
29+
})
30+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
31+
@JsonSubTypes({ //subtype mapping for jackson
32+
@JsonSubTypes.Type(value = NoAuth.class, name = NoAuth._TYPE),
33+
@JsonSubTypes.Type(value = APIKeyAuth.class, name = APIKeyAuth._TYPE),
34+
@JsonSubTypes.Type(value = UsernamePassAuth.class, name = UsernamePassAuth._TYPE)
35+
})
36+
public Object authentication; //the python generator is failing if this is a concrete type
1037

11-
public BaseDatastoreConfig() {
12-
}
38+
@Schema(type = SchemaType.BOOLEAN, required = true, description = "Built In")
39+
public Boolean builtIn;
1340

1441
public BaseDatastoreConfig(Boolean builtIn) {
1542
this.builtIn = builtIn;
1643
}
1744

45+
public BaseDatastoreConfig() {
46+
this.builtIn = false;
47+
}
48+
1849
public abstract String validateConfig();
50+
1951
}

horreum-api/src/main/java/io/hyperfoil/tools/horreum/api/data/datastore/CollectorApiDatastoreConfig.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,30 @@
33
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
44
import org.eclipse.microprofile.openapi.annotations.media.Schema;
55

6+
import io.hyperfoil.tools.horreum.api.data.datastore.auth.APIKeyAuth;
7+
import io.hyperfoil.tools.horreum.api.data.datastore.auth.NoAuth;
8+
69
@Schema(type = SchemaType.OBJECT, required = true, description = "Type of backend datastore")
710
public class CollectorApiDatastoreConfig extends BaseDatastoreConfig {
811

12+
public static final String[] auths = { NoAuth._TYPE, APIKeyAuth._TYPE };
13+
public static final String name = "Collectorapi";
14+
public static final String label = "Collector API";
15+
public static final Boolean builtIn = false;
16+
917
public CollectorApiDatastoreConfig() {
10-
super(false);
1118
}
1219

13-
@Schema(type = SchemaType.STRING, required = true, description = "Collector API KEY")
14-
public String apiKey;
15-
1620
@Schema(type = SchemaType.STRING, required = true, description = "Collector url, e.g. https://collector.foci.life/api/v1/image-stats")
1721
public String url;
1822

1923
@Override
2024
public String validateConfig() {
21-
if ("".equals(apiKey)) {
22-
return "apiKey must be set";
23-
}
24-
if ("".equals(url)) {
25-
return "url must be set";
25+
if (authentication instanceof APIKeyAuth) {
26+
APIKeyAuth apiKeyAuth = (APIKeyAuth) authentication;
27+
if (apiKeyAuth.apiKey.isBlank() || apiKeyAuth.apiKey == null) {
28+
return "apiKey must be set";
29+
}
2630
}
2731

2832
return null;

horreum-api/src/main/java/io/hyperfoil/tools/horreum/api/data/datastore/Datastore.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import io.hyperfoil.tools.horreum.api.data.ProtectedType;
1212

13-
@Schema(type = SchemaType.OBJECT, required = true, description = "Type of backend datastore")
13+
@Schema(type = SchemaType.OBJECT, required = true, description = "Instance of backend datastore")
1414
public class Datastore extends ProtectedType {
1515
@JsonProperty(required = true)
1616
@Schema(description = "Unique Datastore id", example = "101")
@@ -21,14 +21,10 @@ public class Datastore extends ProtectedType {
2121
@Schema(description = "Name of the datastore, used to identify the datastore in the Test definition", example = "Perf Elasticsearch")
2222
public String name;
2323

24-
@NotNull
25-
@JsonProperty(required = true)
26-
@Schema(description = "Is this a built-in datastore? Built-in datastores cannot be deleted or modified", example = "false")
27-
public Boolean builtIn;
28-
2924
@NotNull
3025
@JsonProperty(required = true)
3126
@Schema(type = SchemaType.OBJECT, oneOf = {
27+
CollectorApiDatastoreConfig.class,
3228
ElasticsearchDatastoreConfig.class,
3329
PostgresDatastoreConfig.class
3430
})

0 commit comments

Comments
 (0)