Permalink
Browse files

Add configuration descriptions for api module and add basic parsing o…

…f companion configuration
  • Loading branch information...
schrieveslaach committed Dec 4, 2018
1 parent 1d94388 commit 477c647d86d1daad05a02406548ab7c3194db5c1
@@ -31,3 +31,6 @@ docker-compose up -d

Now, PREvant is running at [`http://localhost`](http://localhost).

# Further Readings

- [All about API image](api/README.md)
@@ -16,7 +16,7 @@ RUN set -eux ; \

WORKDIR /app
COPY --from=builder /usr/local/cargo/bin/api .
COPY res/Rocket.toml /app/Rocket.toml
COPY res/Rocket.toml res/config.toml /app/
EXPOSE 80
ENV ROCKET_ENV=staging
CMD ["./api"]
@@ -0,0 +1,99 @@
The image `aixigo/prevant-api` provides the REST-API in order to deploy Docker containers and to compose them into reviewable application.

# Configuration

In order to configure the REST-API container create a [TOML](https://github.com/toml-lang/toml) file that is mounted to the docker container's path `/app/config.toml`.

## Container Options

Create a table `containers` with following options:

```toml
[containers]
# Restrict memory usage of containers
memory_limit = '1g'
```

## Issue Tracking options

Application names are compared to issues which will be linked to cards on the frontend. Therefore, the REST backend needs to be able to compare the application names with issue tracking information.

Currently, Jira as a tracking system is supported.

```toml
[jira]
host = 'https://jira.example.com'
user = ''
password = ''
```

## Companions

It is possible to start containers that will be started when the client requests to create a new service. For example, if the application requires an [OpenID](https://en.wikipedia.org/wiki/OpenID_Connect) provider, it is possible to create a configuration that starts the provider for each application. Another use case might be a Kafka services that is required by the application.

Furthermore, it is also possible to create containers for each service. For example, for each service a database container could be started.

For these use cases following sections provide example configurations.

### Application Wide

If you want to include an OpenID provider for every application, you could use following configuration.

```toml
[[companions]]
[[companions.application]]
serviceName = 'openid'
image = 'private.example.com/library/opendid:latest'
env = [ 'KEY=VALUE' ]
```

The provided values of `serviceName` and `env` can include the [handlebars syntax](https://handlebarsjs.com/) in order to access dynamic values.

Additionally, you could mount files that are generated from handlebars templates (example contains a properties generation):

```toml
[companions.application.openid.volumes]
"/path/to/volume.properties" = """
remote.services={{#each services~}}
{{~#if (eq type 'instance')~}}
{{name}}:{{port}},
{{~/if~}}
{{~/each~}}
"""
```

#### Template Variables

The list of available handlebars variables:

- `applicationPath`: The root path to the application.
- `services`: An array of the services of the application. Each element has following structure:
- `name`: The service name which is equivalent to the network alias
- `port`: The exposed port of the service
- `type`: The type of service. For example, `instance`, `replica`, `app-companion`, or `service-companion`.

### Service Based

The service-based companions works the in the same way as the application-based services

```toml
[[companions]]
[[companions.services]]
serviceName = 'postgres'
image = 'private.example.com/library/opendid:latest'
env = [ 'KEY=VALUE' ]
[companions.services.postgres.volumes]
"/path/to/volume.properties" == "…"
```


#### Template Variables

The list of available handlebars variables:

- `applicationPath`: The root path to the application.
- `service`: The companion's service containing following fields:
- `name`: The service name which is equivalent to the network alias
- `port`: The exposed port of the service
- `type`: The type of service. For example, `instance`, `replica`, `app-companion`, or `service-companion`.
@@ -0,0 +1,3 @@
# Default configuration
[containers]
memory_limit = '1g'
@@ -148,19 +148,22 @@ impl<'r> Responder<'r> for CreateOrUpdateError {
CreateOrUpdateError::Internal(err) => Response::build()
.sized_body(Cursor::new(
json!({ "error": format!("Internal error: {:?}", err) }).to_string(),
)).header(ContentType::JSON)
))
.header(ContentType::JSON)
.status(Status::InternalServerError)
.ok(),
CreateOrUpdateError::ImagePullErr(err) => Response::build()
.sized_body(Cursor::new(
json!({ "error": format!("Cannot pull image: {:?}", err) }).to_string(),
)).header(ContentType::JSON)
))
.header(ContentType::JSON)
.status(Status::BadRequest)
.ok(),
CreateOrUpdateError::BadServiceConfiguration(err) => Response::build()
.sized_body(Cursor::new(
json!({ "error": format!("{:?}", err) }).to_string(),
)).header(ContentType::JSON)
))
.header(ContentType::JSON)
.status(Status::BadRequest)
.ok(),
}
@@ -83,9 +83,11 @@ impl ListTicketsCommand {
.search()
.iter(format!("issuekey in ({})", issue_keys), &options)
{
Ok(issues) => for issue in issues {
tickets.insert(issue.key.clone(), TicketInfo::from(issue));
},
Ok(issues) => {
for issue in issues {
tickets.insert(issue.key.clone(), TicketInfo::from(issue));
}
}
Err(err) => match err {
GojiError::Fault { code, errors } => {
debug!("No issue for {}: {:?} {:?}", issue_keys, code, errors)
@@ -26,7 +26,6 @@
use std::fmt::{self, Debug, Formatter};
use std::str::FromStr;

use regex::Regex;
use serde::ser::{Serialize, Serializer};
use url::Url;

@@ -43,9 +42,9 @@ pub struct Service {
#[serde(rename_all = "camelCase")]
pub struct ServiceConfig {
service_name: String,
image_repository: String,
registry: Option<String>,
image_user: Option<String>,
image_repository: Option<String>,
image_tag: Option<String>,
env: Option<Vec<String>>,
volumes: Option<Vec<String>>,
@@ -54,56 +53,53 @@ pub struct ServiceConfig {
impl ServiceConfig {
pub fn new(
service_name: &String,
registry: Option<&String>,
image_repository: &String,
env: Option<Vec<String>>,
) -> ServiceConfig {
ServiceConfig {
service_name: service_name.clone(),
registry: match registry {
Some(registry) => Some(registry.clone()),
None => None,
},
image_repository: image_repository.clone(),
registry: None,
image_user: None,
image_repository: None,
image_tag: None,
env,
volumes: None,
}
}

fn get_docker_image_base(&self) -> Result<String, ServiceError> {
let mut service_name = &self.service_name;

if let Some(ref image_repository) = self.image_repository {
if let Some(ref image_user) = self.image_user {
return Ok(image_user.to_owned() + "/" + image_repository);
}
pub fn set_registry(&mut self, registry: &Option<String>) {
self.registry = registry.clone()
}

service_name = image_repository;
}
pub fn set_image_user(&mut self, image_user: &Option<String>) {
self.image_user = image_user.clone()
}

let re: Regex = Regex::new(r"^((\w+)-.+)$").unwrap();
pub fn set_image_tag(&mut self, image_tag: &Option<String>) {
self.image_tag = image_tag.clone()
}

let caps = match re.captures(service_name) {
Some(c) => c,
None => return Err(ServiceError::InvalidServiceName(self.service_name.clone())),
fn get_docker_image_base(&self) -> String {
let image_user = match &self.image_user {
Some(user) => user.clone(),
None => String::from("library"),
};

Ok(String::from(caps.get(2).unwrap().as_str()) + "/" + caps.get(0).unwrap().as_str())
format!("{}/{}", image_user, self.image_repository)
}

pub fn get_docker_image(&self) -> Result<String, ServiceError> {
pub fn get_docker_image(&self) -> String {
let registry = match &self.registry {
None => "docker.io".to_owned(),
None => String::from("docker.io"),
Some(registry) => registry.clone(),
};

Ok(format!(
format!(
"{}/{}:{}",
registry,
self.get_docker_image_base()?,
self.get_docker_image_base(),
self.get_image_tag()
))
)
}

pub fn get_service_name(&self) -> &String {
Oops, something went wrong.

0 comments on commit 477c647

Please sign in to comment.