Skip to content

Commit

Permalink
Strongly typed Datastore configuration - Fixes Hyperfoil#2088
Browse files Browse the repository at this point in the history
  • Loading branch information
johnaohara committed Dec 24, 2024
1 parent 9038d5c commit e12720c
Show file tree
Hide file tree
Showing 19 changed files with 810 additions and 423 deletions.
124 changes: 102 additions & 22 deletions docs/site/content/en/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ paths:
schema:
format: int32
type: integer
/api/config/datastore/types:
get:
tags:
- Config
description: Obtain list of available datastore types
operationId: datastoreTypes
responses:
"200":
description: OK
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/TypeConfig"
/api/config/datastore/{id}:
delete:
tags:
Expand All @@ -77,7 +92,8 @@ paths:
in: path
required: true
schema:
type: string
format: int32
type: integer
responses:
"204":
description: No Content
Expand All @@ -92,7 +108,8 @@ paths:
in: path
required: true
schema:
type: string
format: int32
type: integer
responses:
"200":
description: OK
Expand Down Expand Up @@ -2569,6 +2586,15 @@ paths:
description: No Content
components:
schemas:
APIKeyAuth:
type: object
properties:
type:
description: type
type: string
apiKey:
description: Api key
type: string
Access:
description: "Resources have different visibility within the UI. 'PUBLIC', 'PROTECTED'\
\ and 'PRIVATE'. Restricted resources are not visible to users who do not\
Expand Down Expand Up @@ -2710,17 +2736,26 @@ components:
CollectorApiDatastoreConfig:
description: Type of backend datastore
required:
- authentication
- builtIn
- apiKey
- url
type: object
properties:
authentication:
type: object
oneOf:
- $ref: "#/components/schemas/NoAuth"
- $ref: "#/components/schemas/APIKeyAuth"
- $ref: "#/components/schemas/UsernamePassAuth"
discriminator:
propertyName: type
mapping:
none: "#/components/schemas/NoAuth"
api-key: "#/components/schemas/APIKeyAuth"
username: "#/components/schemas/UsernamePassAuth"
builtIn:
description: Built In
type: boolean
apiKey:
description: Collector API KEY
type: string
url:
description: "Collector url, e.g. https://collector.foci.life/api/v1/image-stats"
type: string
Expand Down Expand Up @@ -2992,13 +3027,12 @@ components:
items:
$ref: "#/components/schemas/ValidationError"
Datastore:
description: Type of backend datastore
description: Instance of backend datastore
required:
- access
- owner
- id
- name
- builtIn
- config
- type
type: object
Expand Down Expand Up @@ -3029,14 +3063,10 @@ components:
\ Test definition"
type: string
example: Perf Elasticsearch
builtIn:
description: Is this a built-in datastore? Built-in datastores cannot be
deleted or modified
type: boolean
example: false
config:
type: object
oneOf:
- $ref: "#/components/schemas/CollectorApiDatastoreConfig"
- $ref: "#/components/schemas/ElasticsearchDatastoreConfig"
- $ref: "#/components/schemas/PostgresDatastoreConfig"
type:
Expand Down Expand Up @@ -3078,25 +3108,29 @@ components:
ElasticsearchDatastoreConfig:
description: Type of backend datastore
required:
- authentication
- builtIn
- url
type: object
properties:
authentication:
type: object
oneOf:
- $ref: "#/components/schemas/NoAuth"
- $ref: "#/components/schemas/APIKeyAuth"
- $ref: "#/components/schemas/UsernamePassAuth"
discriminator:
propertyName: type
mapping:
none: "#/components/schemas/NoAuth"
api-key: "#/components/schemas/APIKeyAuth"
username: "#/components/schemas/UsernamePassAuth"
builtIn:
description: Built In
type: boolean
apiKey:
description: Elasticsearch API KEY
type: string
url:
description: Elasticsearch url
type: string
username:
description: Elasticsearch username
type: string
password:
description: Elasticsearch password
type: string
ErrorDetails:
required:
- type
Expand Down Expand Up @@ -3675,6 +3709,12 @@ components:
testId:
format: int32
type: integer
NoAuth:
type: object
properties:
type:
description: type
type: string
PersistentLog:
description: Persistent Log
required:
Expand All @@ -3699,9 +3739,22 @@ components:
PostgresDatastoreConfig:
description: Built in backend datastore
required:
- authentication
- builtIn
type: object
properties:
authentication:
type: object
oneOf:
- $ref: "#/components/schemas/NoAuth"
- $ref: "#/components/schemas/APIKeyAuth"
- $ref: "#/components/schemas/UsernamePassAuth"
discriminator:
propertyName: type
mapping:
none: "#/components/schemas/NoAuth"
api-key: "#/components/schemas/APIKeyAuth"
username: "#/components/schemas/UsernamePassAuth"
builtIn:
description: Built In
type: boolean
Expand Down Expand Up @@ -4883,6 +4936,21 @@ components:
description: Transformer name
type: string
example: my-dataset-transformer
TypeConfig:
type: object
properties:
enumName:
type: string
name:
type: string
label:
type: string
supportedAuths:
type: array
items:
type: string
builtIn:
type: boolean
UserData:
required:
- id
Expand All @@ -4899,6 +4967,18 @@ components:
type: string
email:
type: string
UsernamePassAuth:
type: object
properties:
type:
description: type
type: string
username:
description: Username
type: string
password:
description: Password
type: string
ValidationError:
required:
- schemaId
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,51 @@
package io.hyperfoil.tools.horreum.api.data.datastore;

import jakarta.validation.constraints.NotNull;

import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.DiscriminatorMapping;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import io.hyperfoil.tools.horreum.api.data.datastore.auth.APIKeyAuth;
import io.hyperfoil.tools.horreum.api.data.datastore.auth.NoAuth;
import io.hyperfoil.tools.horreum.api.data.datastore.auth.UsernamePassAuth;

public abstract class BaseDatastoreConfig {

@Schema(type = SchemaType.BOOLEAN, required = true, description = "Built In")
public Boolean builtIn = true;
@NotNull
@JsonProperty(required = true)
@Schema(type = SchemaType.OBJECT, discriminatorProperty = "type", discriminatorMapping = {
@DiscriminatorMapping(schema = NoAuth.class, value = NoAuth._TYPE),
@DiscriminatorMapping(schema = APIKeyAuth.class, value = APIKeyAuth._TYPE),
@DiscriminatorMapping(schema = UsernamePassAuth.class, value = UsernamePassAuth._TYPE)
}, oneOf = { //subtype mapping for openapi
NoAuth.class,
APIKeyAuth.class,
UsernamePassAuth.class
})
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({ //subtype mapping for jackson
@JsonSubTypes.Type(value = NoAuth.class, name = NoAuth._TYPE),
@JsonSubTypes.Type(value = APIKeyAuth.class, name = APIKeyAuth._TYPE),
@JsonSubTypes.Type(value = UsernamePassAuth.class, name = UsernamePassAuth._TYPE)
})
public Object authentication; //the python generator is failing if this is a concrete type

public BaseDatastoreConfig() {
}
@Schema(type = SchemaType.BOOLEAN, required = true, description = "Built In")
public Boolean builtIn;

public BaseDatastoreConfig(Boolean builtIn) {
this.builtIn = builtIn;
}

public BaseDatastoreConfig() {
this.builtIn = false;
}

public abstract String validateConfig();

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,30 @@
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

import io.hyperfoil.tools.horreum.api.data.datastore.auth.APIKeyAuth;
import io.hyperfoil.tools.horreum.api.data.datastore.auth.NoAuth;

@Schema(type = SchemaType.OBJECT, required = true, description = "Type of backend datastore")
public class CollectorApiDatastoreConfig extends BaseDatastoreConfig {

public static final String[] auths = { NoAuth._TYPE, APIKeyAuth._TYPE };
public static final String name = "Collectorapi";
public static final String label = "Collector API";
public static final Boolean builtIn = false;

public CollectorApiDatastoreConfig() {
super(false);
}

@Schema(type = SchemaType.STRING, required = true, description = "Collector API KEY")
public String apiKey;

@Schema(type = SchemaType.STRING, required = true, description = "Collector url, e.g. https://collector.foci.life/api/v1/image-stats")
public String url;

@Override
public String validateConfig() {
if ("".equals(apiKey)) {
return "apiKey must be set";
}
if ("".equals(url)) {
return "url must be set";
if (authentication instanceof APIKeyAuth) {
APIKeyAuth apiKeyAuth = (APIKeyAuth) authentication;
if ("".equals(apiKeyAuth.apiKey)) {
return "url must be set";
}
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

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

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

@NotNull
@JsonProperty(required = true)
@Schema(description = "Is this a built-in datastore? Built-in datastores cannot be deleted or modified", example = "false")
public Boolean builtIn;

@NotNull
@JsonProperty(required = true)
@Schema(type = SchemaType.OBJECT, oneOf = {
CollectorApiDatastoreConfig.class,
ElasticsearchDatastoreConfig.class,
PostgresDatastoreConfig.class
})
Expand Down
Loading

0 comments on commit e12720c

Please sign in to comment.