← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~lgp171188/launchpad:charming-extract-launchpad-build into launchpad:master

 

Guruprasad has proposed merging ~lgp171188/launchpad:charming-extract-launchpad-build into launchpad:master.

Commit message:
Create a basic reactive charm skeleton for Launchpad

This WIP charm now uses to the ols layer to
* Download and extract the latest Launchpad build artifact from
  the SWIFT storage.
* Install the requirements.


Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/426198
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:charming-extract-launchpad-build into launchpad:master.
diff --git a/charm/.gitignore b/charm/.gitignore
new file mode 100644
index 0000000..da831d3
--- /dev/null
+++ b/charm/.gitignore
@@ -0,0 +1,4 @@
+*.charm
+bundle.yaml
+dist
+tmp
diff --git a/charm/Makefile b/charm/Makefile
new file mode 100644
index 0000000..0988922
--- /dev/null
+++ b/charm/Makefile
@@ -0,0 +1,96 @@
+# The charmcraft tool is shipped as a snap, so make sure it's on $PATH.
+export PATH := $(PATH):/snap/bin
+
+APP_NAME := launchpad
+
+BUILDDIR := $(CURDIR)/dist
+TMPDIR := $(CURDIR)/tmp
+CHARM_LAYERS_DIR := $(TMPDIR)/deps/ols-layers/layer
+CHARM_INTERFACES_DIR := $(TMPDIR)/deps/ols-layers/interface
+
+CHARM_SERIES ?= 18.04
+ARCH := $(shell dpkg --print-architecture)
+charm_file = $(1)_ubuntu-$(CHARM_SERIES)-$(ARCH).charm
+
+BUILD_LABEL = $(shell git rev-parse HEAD)
+TARBALL = $(APP_NAME).tar.gz
+ASSET = ../build/$(BUILD_LABEL)/$(TARBALL)
+
+CHARMS := launchpad
+
+help: ## display this help message
+	@echo "Please use \`make <target>' where <target> is one of"
+	@grep '^[a-zA-Z]' $(MAKEFILE_LIST) | sort | awk -F ':.*?## ' 'NF==2 {printf "\033[36m  %-25s\033[0m %s\n", $$1, $$2}'
+
+all: ## alias to build
+all: build
+
+$(BUILDDIR) $(TMPDIR):
+	@mkdir -p $@
+
+# We have to clone our dependencies by hand rather than letting charmcraft
+# do it, since some of them are in private repositories and charmcraft
+# doesn't have suitable credentials.
+CHARM_DEPS := $(CHARM_LAYERS_DIR)/.done $(CHARM_INTERFACES_DIR)/.done
+$(CHARM_DEPS): $(CURDIR)/dependencies.txt | $(TMPDIR)
+	@echo "Fetching dependencies..."
+	@mkdir -p $(TMPDIR)/deps
+	@cd $(TMPDIR)/deps && codetree $<
+	@touch $(CHARM_DEPS)
+
+build: ## build all the charms
+build: $(foreach charm,$(CHARMS),build-$(charm))
+
+build-launchpad: ## build the launchpad charm
+build-launchpad: dist/$(call charm_file,launchpad)
+
+dist/%_ubuntu-$(CHARM_SERIES)-$(ARCH).charm: $(CHARM_DEPS) | $(BUILDDIR)
+	@echo "Building $*..."
+	@rm -rf $*/tmp
+	@cp -a tmp $*/tmp
+	@cd $* && charmcraft pack
+	@cp -a $*/$(call charm_file,$*) dist/
+	@rm -rf $*/tmp
+
+clean: ## clean the build environment
+clean: $(foreach charm,$(CHARMS),clean-$(charm))
+	@find . -name \*.pyc -delete
+	@find . -depth -name '__pycache__' -exec rm -rf '{}' \;
+	@rm -f bundle.yaml
+	@rm -f layer/*/codetree-collect-info.yaml
+	@rm -rf $(BUILDDIR) $(TMPDIR)
+
+clean-%:
+	@echo "Cleaning $*..."
+	@cd $* && charmcraft clean
+	@rm -f dist/$(call charm_file,$*)
+
+bundle.yaml: ## create the bundle.yaml file from the bundle.yaml.in template
+bundle.yaml: bundle.yaml.in
+	sed \
+	    -e 's/%BUILD_LABEL%/$(BUILD_LABEL)/g' \
+	    bundle.yaml.in >bundle.yaml
+
+deploy: ## deploy the built charm
+deploy: build bundle.yaml
+	@echo "Deploying $(APP_NAME)..."
+	@juju deploy ./bundle.yaml
+
+payload: ## build a launchpad tarball
+payload: $(ASSET)
+$(ASSET):
+	@echo "Building asset for $(BUILD_LABEL)..."
+	@$(MAKE) -C .. build-tarball
+
+
+setup-jenkaas: ## prepare a Jenkins-as-a-service container for charm building
+setup-jenkaas:
+	sudo systemctl stop snapd.socket
+	sudo systemctl stop snapd
+	echo SNAPPY_STORE_NO_CDN=1 | sudo tee -a /etc/environment >/dev/null
+	echo SNAPPY_TESTING=1 | sudo tee -a /etc/environment >/dev/null
+	sudo systemctl start snapd.socket
+	sudo snap install --classic charm
+
+.PHONY: $(foreach charm,$(CHARMS),build-$(charm))
+.PHONY: all build clean deploy payload setup-jenkaas
diff --git a/charm/bundle.yaml.in b/charm/bundle.yaml.in
new file mode 100644
index 0000000..3a8c1af
--- /dev/null
+++ b/charm/bundle.yaml.in
@@ -0,0 +1,10 @@
+series: bionic
+description: "launchpad development bundle"
+applications:
+  launchpad:
+    charm: ./dist/launchpad_ubuntu-18.04-amd64.charm
+    num_units: 1
+    options:
+      build_label: "%BUILD_LABEL%"
+      swift_storage_url: "https://radosgw.ps5.canonical.com/swift/v1/AUTH_318a449e4c8e40e2865c120a597a9644";
+      swift_container_name: "launchpad-builds"
diff --git a/charm/dependencies.txt b/charm/dependencies.txt
new file mode 100644
index 0000000..e575f98
--- /dev/null
+++ b/charm/dependencies.txt
@@ -0,0 +1,2 @@
+ols-layers			git+ssh://git.launchpad.net/~ubuntuone-pqm-team/ols-charm-deps/+git/ols-layers;revno=df20c87d
+charm-wheels		git+ssh://git.launchpad.net/~ubuntuone-hackers/ols-charm-deps/+git/wheels;revno=fe523e25
diff --git a/charm/launchpad/charmcraft.yaml b/charm/launchpad/charmcraft.yaml
new file mode 100644
index 0000000..5b50137
--- /dev/null
+++ b/charm/launchpad/charmcraft.yaml
@@ -0,0 +1,20 @@
+type: charm
+bases:
+  - build-on:
+    - name: ubuntu
+      channel: "18.04"
+    run-on:
+    - name: ubuntu
+      channel: "18.04"
+parts:
+  launchpad:
+    source: .
+    plugin: reactive
+    build-snaps: [charm]
+    build-environment:
+      - CHARM_LAYERS_DIR: tmp/deps/ols-layers/layer
+      - CHARM_INTERFACES_DIR: tmp/deps/ols-layers/interface
+      - PIP_NO_INDEX: "true"
+      - PIP_FIND_LINKS: tmp/deps/charm-wheels
+    stage:
+      - -tmp
diff --git a/charm/launchpad/config.yaml b/charm/launchpad/config.yaml
new file mode 100644
index 0000000..adc4e2c
--- /dev/null
+++ b/charm/launchpad/config.yaml
@@ -0,0 +1,8 @@
+options:
+  # layer-apt
+  install_sources:
+    default: |
+      - ppa:launchpad/ppa
+  install_keys:
+    default: |
+      - null  # PPA keys securely added via Launchpad.
diff --git a/charm/launchpad/icon.svg b/charm/launchpad/icon.svg
new file mode 100644
index 0000000..b2889cc
--- /dev/null
+++ b/charm/launchpad/icon.svg
@@ -0,0 +1 @@
+<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg"; viewBox="0 0 165.39062 165.39062"><defs><style>.cls-1{fill:#e9500e;}.cls-2{fill:#fff;}</style></defs><rect class="cls-1" width="165.39062" height="165.39062"/><path class="cls-2" d="M29.63876,57.97189C43.189,67.692,61.13456,69.25577,77.65457,62.15038c16.25576-6.87157,27.74036-21.43444,29.97828-38.0075.04663-.34331.11016-.81367-1.59861-1.24044l-10.10934-2.197c-.3254-.04494-.79136-.04967-1.15258,1.22455C91.37844,36.07384,84.34062,45.04243,72.6347,50.1123c-11.77316,5.10029-23.18748,4.05279-35.91893-3.29386-.58119-.27843-.91909-.26086-1.45568.52577l-5.77947,8.65163A1.34512,1.34512,0,0,0,29.63876,57.97189Z" transform="translate(0.39062 0.39062)"/><path class="cls-2" d="M79.86106,139.66026l10.3631.565c1.74155.03446,1.79122-.42981,1.83717-.77312,2.23826-16.5734-4.97222-33.66107-18.81739-44.59422C59.196,83.62132,41.47815,80.36935,25.83365,86.14747a1.33956,1.33956,0,0,0-.67918,1.85373l3.28,9.88226c.30952.90153.62816,1.011,1.26443.89409,14.22464-3.70543,25.50717-1.68748,35.50635,6.3512,9.94174,7.9934,14.34865,18.50754,13.86883,33.08867C79.08524,139.50144,79.53735,139.615,79.86106,139.66026Z" transform="translate(0.39062 0.39062)"/><path class="cls-2" d="M86.50488,70.59048a10.50817,10.50817,0,0,0-1.39587-.09461A9.35237,9.35237,0,0,0,79.39915,72.382a9.61981,9.61981,0,1,0,7.10573-1.79156Z" transform="translate(0.39062 0.39062)"/><path class="cls-2" d="M138.26869,53.18923,133.457,43.97736c-.68628-1.51583-1.22793-1.36985-1.79594-1.17657-15.382,6.63165-25.99848,21.22156-28.40434,39.03776-2.40755,17.82971,3.97169,34.72681,17.0647,45.19906a1.177,1.177,0,0,0,.90794.32844,1.48362,1.48362,0,0,0,.99546-.54l6.76175-8.11166c.62342-.78393.35783-1.18333.0321-1.52461-10.60639-10.44454-14.5764-20.81677-12.84905-33.60769,1.73682-12.86121,8.51918-22.08254,21.34457-29.019C138.52854,53.95289,138.36533,53.421,138.26869,53.18923Z" transform="translate(0.39062 0.39062)"/></svg>
\ No newline at end of file
diff --git a/charm/launchpad/layer.yaml b/charm/launchpad/layer.yaml
new file mode 100644
index 0000000..9b9e9bb
--- /dev/null
+++ b/charm/launchpad/layer.yaml
@@ -0,0 +1,15 @@
+includes:
+  - layer:basic
+  - layer:ols
+options:
+  apt:
+    packages:
+      - launchpad-dependencies
+  ols:
+    service_name: launchpad
+    config_filename: launchpad.conf
+    user: launchpad
+    tarball_payload: true
+    symlink_switch_payload: true
+    python_bin: /usr/bin/python3
+repo: https://git.launchpad.net/launchpad
diff --git a/charm/launchpad/metadata.yaml b/charm/launchpad/metadata.yaml
new file mode 100644
index 0000000..58c8787
--- /dev/null
+++ b/charm/launchpad/metadata.yaml
@@ -0,0 +1,13 @@
+name: launchpad
+display-name: launchpad
+summary: Launchpad web application
+maintainer: Guruprasad <guruprasad.ln@xxxxxxxxxxxxx>
+ddisescription: |
+  Launchpad is an open source suite of tools that help people and teams
+  to work together on software projects.
+tags:
+  # https://juju.is/docs/charm-metadata#heading--charm-store-fields
+  - network
+series:
+  - bionic
+subordinate: false
diff --git a/charm/launchpad/reactive/launchpad.py b/charm/launchpad/reactive/launchpad.py
new file mode 100644
index 0000000..7cdf698
--- /dev/null
+++ b/charm/launchpad/reactive/launchpad.py
@@ -0,0 +1,47 @@
+# Copyright 2022 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+import subprocess
+
+from charmhelpers.core import hookenv
+from charms.reactive import (
+    remove_state,
+    set_state,
+    when,
+    when_not,
+    )
+from ols import base
+
+
+# Monkey-patch layer:ols.
+def create_virtualenv(wheels_dir, codedir, python_exe):
+    subprocess.run(
+        ['make', 'compile', 'PYTHON={}'.format(python_exe)],
+        cwd=codedir, check=True)
+
+
+base.create_virtualenv = create_virtualenv
+
+
+@when('ols.configured')
+@when_not('service.configured')
+def configure():
+    hookenv.log('Hello world!')
+    set_state('service.configured')
+
+
+@when('service.configured')
+def check_is_running():
+    hookenv.status_set('active', 'Ready')
+
+
+@when('config.changed.build_label')
+def build_label_changed():
+    remove_state('ols.service.installed')
+    remove_state('ols.configured')
+    remove_state('service.configured')
+
+
+@when('config.changed')
+def config_changed():
+    remove_state('service.configured')
diff --git a/charm/launchpad/tests/00-setup b/charm/launchpad/tests/00-setup
new file mode 100755
index 0000000..f0616a5
--- /dev/null
+++ b/charm/launchpad/tests/00-setup
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+sudo add-apt-repository ppa:juju/stable -y
+sudo apt-get update
+sudo apt-get install amulet python-requests -y
diff --git a/charm/launchpad/tests/10-deploy b/charm/launchpad/tests/10-deploy
new file mode 100755
index 0000000..a0fa797
--- /dev/null
+++ b/charm/launchpad/tests/10-deploy
@@ -0,0 +1,42 @@
+#!/usr/bin/python3
+
+import unittest
+
+import amulet
+import requests
+
+
+class TestCharm(unittest.TestCase):
+    def setUp(self):
+        self.d = amulet.Deployment()
+
+        self.d.add('launchpad')
+        self.d.expose('launchpad')
+
+        self.d.setup(timeout=900)
+        self.d.sentry.wait()
+
+        self.unit = self.d.sentry['launchpad'][0]
+
+    def test_service(self):
+        # test we can access over http
+        page = requests.get(
+            'http://{}'.format(self.unit.info['public-address'])
+        )
+        self.assertEqual(page.status_code, 200)
+        # Now you can use self.d.sentry[SERVICE][UNIT] to address each
+        # of the units and perform more in-depth steps. Each
+        # self.d.sentry[SERVICE][UNIT] has the following methods:
+        # - .info - An array of the information of that unit from Juju
+        # - .file(PATH) - Get the details of a file on that unit
+        # - .file_contents(PATH) - Get plain text output of PATH file from
+        #    that unit
+        # - .directory(PATH) - Get details of directory
+        # - .directory_contents(PATH) - List files and folders in PATH on
+        #   that unit
+        # - .relation(relation, service:rel) - Get relation data from return
+        #   service
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/charm/packages.txt b/charm/packages.txt
new file mode 100644
index 0000000..c33fce5
--- /dev/null
+++ b/charm/packages.txt
@@ -0,0 +1,3 @@
+flake8
+python-codetree
+squashfuse

Follow ups