diff --git a/cyclos-ui/hooks/init b/cyclos-ui/hooks/init new file mode 100755 index 0000000..7ed0832 --- /dev/null +++ b/cyclos-ui/hooks/init @@ -0,0 +1,22 @@ +#!/bin/bash + +## Init is run on host +## For now it is run every time the script is launched, but +## it should be launched only once after build. + +## Accessible variables are: +## - SERVICE_NAME Name of current service +## - DOCKER_BASE_IMAGE Base image from which this service might be built if any +## - SERVICE_DATASTORE Location on host of the DATASTORE of this service +## - SERVICE_CONFIGSTORE Location on host of the CONFIGSTORE of this service + +set -e + +#!/bin/bash +## Should be executable N time in a row with same result. + +. lib/common + +set -e + +cyclos_ui.make_base_config_file \ No newline at end of file diff --git a/cyclos-ui/hooks/pre_deploy b/cyclos-ui/hooks/pre_deploy new file mode 100755 index 0000000..660dee3 --- /dev/null +++ b/cyclos-ui/hooks/pre_deploy @@ -0,0 +1,40 @@ +#!/bin/bash +## Should be executable N time in a row with same result. + +. lib/common + +set -e + + +## if I'm not linked to a cyclos-server, then complain +if read-0 ts _ _ < <(get_service_relation "$SERVICE_NAME" "cyclos-server"); then + debug "cyclos-server relation fullfilled" + + if read-0 wps wpcfg _ < <(get_service_relation "$ts" "web-proxy"); then + debug "found web-proxy relation" + else + ## XXXvlab: relation dependence as this one could actually be implemented in compose-core + err "cyclos-server relation requires the server to have a web-proxy relation to be set" + exit 1 + fi + + web_proxy_relation_dir=$(get_relation_data_dir "$ts" "$wps" "web-proxy") || { + err "Failed to find relation file" + exit 1 + } + + web_proxy_relation_config=$(cat "$web_proxy_relation_dir/data") || exit 2 + + url=$(e "$web_proxy_relation_config" | shyaml get-value url) || { + err "Couldn't get domain information in ${DARKCYAN}web-proxy${NORMAL} relation's data." + exit 1 + } + + if ! cyclos_ui.conf_add "apiRoot: $url/api"; then + err "Couldn't configure api root correctly." + exit 1 + fi + +fi + +cyclos_ui.generate_website \ No newline at end of file diff --git a/cyclos-ui/lib/common b/cyclos-ui/lib/common new file mode 100644 index 0000000..80bf892 --- /dev/null +++ b/cyclos-ui/lib/common @@ -0,0 +1,97 @@ + +YML_CONFIG_PATH=/conf.yml +LOCAL_YML_CONFIG_PATH="$SERVICE_CONFIGSTORE$YML_CONFIG_PATH" +HOST_YML_CONFIG_PATH="$HOST_CONFIGSTORE/$SERVICE_NAME$YML_CONFIG_PATH" + + +CONFIG_PATH=/setup.ts +LOCAL_CONFIG_PATH="$SERVICE_CONFIGSTORE$CONFIG_PATH" +HOST_CONFIG_PATH="$HOST_CONFIGSTORE/$SERVICE_NAME$CONFIG_PATH" + +DEST_PATH=/var/www/cyclos-ui +LOCAL_DEST_PATH="$SERVICE_DATASTORE$DEST_PATH" +HOST_DEST_PATH="$HOST_DATASTORE/$SERVICE_NAME$DEST_PATH" + + +cyclos_ui.build_builder_image() { + local last_line + if out=$(cd "$CHARM_PATH/misc/builder" && docker build . 2>&1); then + last_line="${out##*$'\n'}" + if [[ "${last_line}" =~ ^"Successfully built "[a-f0-9]+$ ]]; then + echo "${last_line##* }" + return 0 + else + err "Couldn't find image id:" + fi + else + err "Failed to build the builder image:" + fi + e "$out" | prefix " ${DARKGRAY}|${NORMAL} " >&2 + return 1 +} + + +cyclos_ui.make_base_config_file() { + local cfg_file_content builder_image_id + # builder_image_id=$(cyclos_ui.build_builder_image) || return 1 + # cfg_file_content=$(docker run --rm "$builder_image_id" cat src/app/setup.ts) || { + # err "Couldn't access 'src/app/setup.ts' in given image." + # return 1 + # } + service_def=$(get_compose_service_def "$SERVICE_NAME") || return 1 + cfg_file_content=$(echo "$service_def" | shyaml -y get-value "options" 2>/dev/null) || true + mkdir -p "${LOCAL_YML_CONFIG_PATH%/*}" && + e "$cfg_file_content" > "$LOCAL_YML_CONFIG_PATH" +} + + +cyclos_ui.generate_website() { + local builder_image_id hash_file="$LOCAL_DEST_PATH/.hash" + hash=$(hash_get < "$LOCAL_YML_CONFIG_PATH") + + if [ -f "${hash_file}" ]; then + if [[ "$(cat "${hash_file}")" == "$hash" ]]; then + return 0 + else + [ -d "$LOCAL_DEST_PATH" ] && echo rm -rf "${LOCAL_DEST_PATH}" + fi + fi + builder_image_id=$(cyclos_ui.build_builder_image) || return 1 + cfg_file_content=$(docker run --rm "$builder_image_id" cat src/app/setup.ts) || { + err "Couldn't access 'src/app/setup.ts' in given image." + return 1 + } + ## remove last '}' + cfg_file_content="${cfg_file_content%\}*}" + while read-0 k v; do + json=$(e "$v" | yaml2json) || { + err "Failed to correct yaml to json" + return 1 + } + cfg_file_content+=" Configuration.$(e "$k" | shyaml get-value) = $json;"$'\n'"" + done < <(cat "$LOCAL_YML_CONFIG_PATH" | shyaml -y key-values-0) + cfg_file_content+="}" + mkdir -p "${LOCAL_CONFIG_PATH%/*}" && + e "$cfg_file_content" > "$LOCAL_CONFIG_PATH" + docker run --rm \ + -v "$HOST_CONFIG_PATH:/opt/apps/cyclos-ui/src/app/setup.ts:ro" \ + -v "$HOST_DEST_PATH:/opt/apps/cyclos-ui/dist:rw" \ + "${builder_image_id}" \ + npm run build >&2 || { + err "Failed to build new sources." + return 1 + } + e "$hash" > "$hash_file" +} + + +cyclos_ui.conf_add() { + local yaml="$1" + prev=$([ -f "$LOCAL_YML_CONFIG_PATH" ] && cat "$LOCAL_YML_CONFIG_PATH") + if ! out=$(merge_yaml_str "$prev" "$yaml"); then + err "Couldn't merge new configuration." + exit 1 + fi + mkdir -p "${LOCAL_CONFIG_PATH%/*}" && + e "$out" > "$LOCAL_YML_CONFIG_PATH" +} \ No newline at end of file diff --git a/cyclos-ui/metadata.yml b/cyclos-ui/metadata.yml new file mode 100644 index 0000000..67d8ba5 --- /dev/null +++ b/cyclos-ui/metadata.yml @@ -0,0 +1,58 @@ +description: "Cyclos UI" +maintainer: "Valentin Lab " +subordinate: true + +data-resources: + - /var/www/cyclos-ui + +default-options: + apiRoot: api + appTitle: Cyclos + appTitleSmall: Cyclos frontend + appTitleMenu: Cyclos menu + + +uses: + backup: + constraint: recommended + auto: pair + solves: + backup: "Automatic regular backup" + default-options: + ## First pattern matching wins, no pattern matching includes. + ## include-patterns are checked first, then exclude-patterns + ## Patterns rules: + ## - ending / for directory + ## - '*' authorized + ## - must start with a '/', will start from $SERVICE_DATASTORE + exclude-patterns: + publish-dir: + #constraint: required | recommended | optional + #auto: pair | summon | none ## default: pair + scope: container + constraint: required + auto: summon + solves: + container: "main running server" + default-options: + location: !var-expand "$DATASTORE/$BASE_SERVICE_NAME/var/www/cyclos-ui" + # data-dirs: ## write permission for web-app + # - . + apache-custom-rules: + - | + + RewriteEngine On + RewriteBase / + RewriteRule ^index\.html$ - [L] + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule . /index.html [L] + + cyclos-server: + #constraint: required | recommended | optional + #auto: pair | summon | none ## default: pair + constraint: optional + auto: pair + solves: + container: "api server" + default-options: diff --git a/cyclos-ui/misc/builder/Dockerfile b/cyclos-ui/misc/builder/Dockerfile new file mode 100644 index 0000000..226473c --- /dev/null +++ b/cyclos-ui/misc/builder/Dockerfile @@ -0,0 +1,27 @@ +FROM alpine:3.12 + +ENV CYCLOSUI_RELEASE=2.0.0 + +RUN apk add wget npm +# COPY ./patches/*.patch /tmp +RUN mkdir -p /opt/apps/cyclos-ui && \ + cd /opt/apps/cyclos-ui && \ + wget "https://github.com/cyclosproject/cyclos4-ui/archive/${CYCLOSUI_RELEASE}.tar.gz" && \ + tar -xzf "${CYCLOSUI_RELEASE}.tar.gz" && \ + rm "${CYCLOSUI_RELEASE}.tar.gz" && \ + mv cyclos4-ui-"${CYCLOSUI_RELEASE}"/* cyclos4-ui-"${CYCLOSUI_RELEASE}"/.[a-z]* . && \ + rmdir cyclos4-ui-"${CYCLOSUI_RELEASE}" && \ + # cat /tmp/*.patch | patch -p1 && \ + # mkdir -p /etc/cyclos-ui /var/lib/cyclos-ui && \ + # ln -sf /var/lib/cyclos-ui /opt/apps/cyclos-ui/storage + true + +RUN cd /opt/apps/cyclos-ui && \ + npm install + +RUN cd /opt/apps/cyclos-ui && \ + npm run generate + +WORKDIR /opt/apps/cyclos-ui + + diff --git a/cyclos/metadata.yml b/cyclos/metadata.yml index 499fde4..35a33b8 100644 --- a/cyclos/metadata.yml +++ b/cyclos/metadata.yml @@ -5,6 +5,9 @@ config-resources: data-resources: - /var/log/cyclos +provides: + cyclos-server: + default-options: uses: