<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>snaums.de - golang</title><link href="https://www.snaums.de/" rel="alternate"></link><link href="https://www.snaums.de/feed/tag-golang.atom.xml" rel="self"></link><id>https://www.snaums.de/</id><updated>2020-01-11T16:30:00+01:00</updated><entry><title>My very own Continuous Integration Server (mvoCI)</title><link href="https://www.snaums.de/informatik/mvoci-introduction.html" rel="alternate"></link><published>2020-01-11T16:30:00+01:00</published><updated>2020-01-11T16:30:00+01:00</updated><author><name>snaums</name></author><id>tag:www.snaums.de,2020-01-11:/informatik/mvoci-introduction.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;This article has been deprecated by Golangs Modules.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;About a year ago, I changed by website (which you are visiting right about now) from a Wordpress based system to a static website generator called &lt;em&gt;Pelican&lt;/em&gt; [&lt;a href="https://www.getpelican.com"&gt;pelican&lt;/a&gt;]. Since then I feared building that website and that it may become one day …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;This article has been deprecated by Golangs Modules.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;About a year ago, I changed by website (which you are visiting right about now) from a Wordpress based system to a static website generator called &lt;em&gt;Pelican&lt;/em&gt; [&lt;a href="https://www.getpelican.com"&gt;pelican&lt;/a&gt;]. Since then I feared building that website and that it may become one day not buildable, e.g. because I loose the knowledge on how to build the damn thing. Also deploying new versions of the website would be quite a hassle, as the new HTML-files would have been copied over to the server manually.&lt;/p&gt;
&lt;p&gt;But fear not! There are solutions to that, in the form of continuous integration servers. Well... I tried &lt;em&gt;Jenkins&lt;/em&gt; [&lt;a href="https://jenkins.org"&gt;jenkins&lt;/a&gt;]. Jenkins is a really powerful Java-software, which can do nearly anything you want. However, it is a Java-software. Once it has got its heap-memory, it will never give it back. This would be swell, if the server running it has enough RAM to spare, however my vServer has only 2 GB. And Jenkins after building my website once (a quite simple website, I might add) ate nearly half of it. Jenkins alone! After an incident, where Jenkins spammed a log-file and also ate the disk-space, I swiftly got rid of it.&lt;/p&gt;
&lt;p&gt;There are also other Continuous Integration servers, but most of them are quite overblown and full of features I would never need. A very simple one is &lt;em&gt;flux-ci&lt;/em&gt; [&lt;a href="https://github.com/NiklasRosenstein/flux-ci"&gt;flux-ci&lt;/a&gt;]. It's written in Python, based on Flask and is an easy to use, straightforward solution to my problem. Looking through the code at the time (about a year back), I wasn't satisfied and began work to modify flux-ci to my hearts content. Eventually I stopped to work on that code, and began programming my very own CI-server (mvoCI).&lt;/p&gt;
&lt;p&gt;While it shares the templates, i.e. the optics with flux-ci (I've asked), it is its very own beast, written in Go [&lt;a href="https://www.golang.org"&gt;golang&lt;/a&gt;], based on &lt;em&gt;echo&lt;/em&gt; and &lt;em&gt;gorm&lt;/em&gt; for object-oriented interface to a relational database.&lt;/p&gt;
&lt;h2 id="what-can-it-do"&gt;What can it do?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;tl;dr:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;build git repositories on user input or repo-push&lt;/li&gt;
&lt;li&gt;public repositories (builds can be viewed and artifacts downloaded without auth)&lt;/li&gt;
&lt;li&gt;query information about repos and builds, as well as build specific branches and commits via a REST API&lt;/li&gt;
&lt;li&gt;deploy e.g. a pelican website by abusing the build-script&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I tried to stay on the simple side with mvoCI. It can build your git-repository, either when you hit build, or when someone pushes into the repository, if you have a webhook configured in the git-server of your choice. I personally use &lt;em&gt;gitea&lt;/em&gt; [&lt;a href="https://gitea.io"&gt;gitea&lt;/a&gt;] in conjunction with that.&lt;/p&gt;
&lt;p&gt;You can have several users, with their own repositories. You can have repositories, which are public, i.e. their builds can be downloaded without authentication. I recently added a REST-API interface, which can be used to query information about repos and builds, and to build a specific repository, commit and branch. More work needs to be done, so someone could be able to build an accompanying app to mvoCI in the future.&lt;/p&gt;
&lt;p&gt;I already use mvoCI to deploy new versions of my website. Essentially I am abusing locality; the user executing mvoCI has write access to the folder of the website. After building the website, its www-folder is copied over to the apache DocumentRoot. Deployment of simple services via this technique seems possible. For deploying services or updates over the boundaries of machines the API could be used; this is part of the work to be done in future.&lt;/p&gt;
&lt;h3 id="what-is-planned"&gt;What is planned?&lt;/h3&gt;
&lt;p&gt;At the time of writing, the API is a bit bare bones. While querying information is already possible, it is not possible to edit information or delete any objects. Also querying if there are any new builds for a repository or even push-notifications if that is the case it not possible yet.&lt;/p&gt;
&lt;h4 id="webhook-filters"&gt;Webhook-Filters&lt;/h4&gt;
&lt;p&gt;An idea in a semi-abandoned state is the introduction of filters for webhooks. Git-Servers send an event-type with their webhook, so they can indicate, whether the user pushed into the repository of created a new release or whatever. A idea is extend the quite simple model of a repository, with one single build script, to a repo with a list of filters and attached build scripts. So a repo could "listen" to several events and handle them differently, maybe even building the repo several times for a single webhook event. &lt;/p&gt;
&lt;p&gt;A generic filter-interface would also allow to do timed builds on more frequented repositories, think about Firefox, where you would want automatic tests for every commit, but maybe would want a release-build only every night or week. A pattern-based method for keeping builds would fit right into that.&lt;/p&gt;
&lt;p&gt;This would indeed make mvoCI more powerful, but also bigger and would require a rewrite of some parts of the code, which I'm not willing to do yet. I've started work on it and may be restarting it in the future, however at the moment, mvoCI is more than capable of handling what I want from it.&lt;/p&gt;
&lt;h2 id="how-do-i-get-it_2"&gt;How do I get it?&lt;/h2&gt;
&lt;h3 id="tldr"&gt;tl;dr&lt;/h3&gt;
&lt;p&gt;Make sure you have at least the go-toolchain in version 1.12.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://git.stefannaumann.de/snaums/mvoCI.git&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mvoCI&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;GOPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;src/mvoCI&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="c1"&gt;# move the code to the go-dir&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;extglob&lt;span class="w"&gt; &lt;/span&gt;dotglob&lt;/span&gt;
&lt;span class="code-line"&gt;mv&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;(&lt;/span&gt;src&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;src/mvoCI/&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;dotglob&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="nb"&gt;pushd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;src/mvoCI&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="c1"&gt;# install build dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;make&lt;span class="w"&gt; &lt;/span&gt;dep&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="c1"&gt;# build and move artifacts to dist&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;make&lt;span class="w"&gt; &lt;/span&gt;dist&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="c1"&gt;# cleanup&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;web&lt;span class="w"&gt; &lt;/span&gt;hook&lt;span class="w"&gt; &lt;/span&gt;log&lt;span class="w"&gt; &lt;/span&gt;Makefile&lt;span class="w"&gt; &lt;/span&gt;main.go&lt;span class="w"&gt; &lt;/span&gt;mvo.cfg&lt;span class="w"&gt; &lt;/span&gt;static&lt;span class="w"&gt; &lt;/span&gt;repo&lt;span class="w"&gt; &lt;/span&gt;static&lt;span class="w"&gt; &lt;/span&gt;views&lt;span class="w"&gt; &lt;/span&gt;core&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;builds&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="nb"&gt;popd&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="c1"&gt;# cleanup for packaging&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;mv&lt;span class="w"&gt; &lt;/span&gt;src/mvoCI/dist/*&lt;span class="w"&gt; &lt;/span&gt;.&lt;/span&gt;
&lt;span class="code-line"&gt;rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;src&lt;span class="w"&gt; &lt;/span&gt;pkg&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="the-long-version"&gt;The long version&lt;/h3&gt;
&lt;p&gt;I'm currently testing building and packaging mvoCI with my own mvoCI instance. Until I make that public, the script under tl;dr is sufficient to build mvoCI. &lt;/p&gt;
&lt;p&gt;The code is hosted on my &lt;a href="https://git.stefannaumann.de/snaums/mvoCI"&gt;gitea-instance&lt;/a&gt;. Clone the repository and move inside. &lt;/p&gt;
&lt;h4 id="requirements"&gt;Requirements&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;golang in version 1.12 or higher&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you haven't gotten the go toolchain in the correct version, you can install it from the Linux repositories. Make sure you get at least version 1.12. If you are running Debian 10 (stable), you will not get the correct version. You can get a working toolchain from [&lt;a href="https://golang.org/dl/"&gt;golang-dl&lt;/a&gt;] in that circumstance or when running Windows or Mac OSX.&lt;/p&gt;
&lt;h4 id="build-time-requirements"&gt;Build time requirements&lt;/h4&gt;
&lt;p&gt;As of time of writing mvoCI depends on the following golang-libraries&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;github.com/jinzhu/gorm &lt;em&gt;(plus it's dependencies for DB access)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;github.com/labstack/echo&lt;/li&gt;
&lt;li&gt;golang.org/x/crypto/bcrypt&lt;/li&gt;
&lt;li&gt;github.com/foolin/goview&lt;/li&gt;
&lt;li&gt;github.com/foolin/goview/supports/echoview-v4&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don't want to bother, just run &lt;code&gt;make dep&lt;/code&gt;, which will install all necessary library dependencies. If you notice any problems, don't hesitate to contact me.&lt;/p&gt;
&lt;h4 id="building-mvoci"&gt;Building mvoCI&lt;/h4&gt;
&lt;p&gt;Make sure it is in your &lt;code&gt;$GOPATH&lt;/code&gt;. Either you move the cloned repository to &lt;code&gt;~/go/src/mvoCI&lt;/code&gt; (which would be the default &lt;code&gt;$GOPATH&lt;/code&gt;) or you overwrite the environment variable. Make sure you keep the tree intact, i.e. &lt;code&gt;$GOPATH/src/mvoCI/&amp;lt;repo content&amp;gt;&lt;/code&gt;. You will need to redownload the dependencies into the correct &lt;code&gt;$GOPATH&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;Change in the directory and run &lt;code&gt;make mvobuild&lt;/code&gt; or &lt;code&gt;make dist&lt;/code&gt; . Both will build mvoCI, but &lt;code&gt;dist&lt;/code&gt; will move all necessary files to the &lt;code&gt;dist&lt;/code&gt; folder, so you only need to move that to where you want and can start running the application.&lt;/p&gt;
&lt;h2 id="set-up-and-usage_2"&gt;Set-up and Usage&lt;/h2&gt;
&lt;h3 id="security"&gt;Security&lt;/h3&gt;
&lt;p&gt;Keep in mind, that mvoCI can execute arbitrary bash-code on your machine. If you are running it on your most valuable server, make sure you know what you are doing and keep locked down, so it cannot destroy any other services your machine provides.&lt;/p&gt;
&lt;p&gt;At least execute it as a different user from any other. Create a new user, give it a home, copy the &lt;code&gt;dist&lt;/code&gt; folder into that. Then you could use systemd to execute the program with the correct user at startup. You may use this config file for systemd:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="code-line"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mvoCI&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;syslog.target&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mysqld.service&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="c1"&gt;#After=postgresql.service&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="k"&gt;[Service]&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;RestartSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2s&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;simple&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mvo&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;Group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mvo&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/mvo&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/mvo/mvo&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;USER=mvo HOME=/home/mvo&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="k"&gt;[Install]&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;&lt;/span&gt;
&lt;span class="code-line"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="installing"&gt;Installing&lt;/h3&gt;
&lt;p&gt;For the first installation you will need to run the &lt;code&gt;mvo&lt;/code&gt; executable with the parameter &lt;code&gt;--install&lt;/code&gt;. This will set the program in Installation-mode. This allows you to set the database parameters and credentials for the first user. It will create a config file &lt;code&gt;mvo.cfg&lt;/code&gt;. After the installation process is done, stop the process and run the program without any parameters for production. &lt;/p&gt;
&lt;p&gt;See through the configuration options in &lt;code&gt;mvo.cfg&lt;/code&gt;. It's a JSON-representation of the struct in &lt;code&gt;core/config.go&lt;/code&gt;. Changing anything will require a restart of the application.&lt;/p&gt;
&lt;h3 id="running"&gt;Running&lt;/h3&gt;
&lt;p&gt;Once it is set-up and running you can login with your credentials, create repositories and new users. You can also LoginTokens, for using the API. An API-call needs a valid token in the &lt;code&gt;mvoCi_session&lt;/code&gt; token.&lt;/p&gt;
&lt;h2 id="what-to-do-next_1"&gt;What to do next&lt;/h2&gt;
&lt;p&gt;That is up to you. I'd appreciate bug-reports and pull requests to be reported at the &lt;a href="http://git.stefannaumann.de/snaums/mvoCI"&gt;repository&lt;/a&gt;. Every polite feedback is good input, what to improve. This includes feature-requests as well as bug-reports. &lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;p&gt;[flux-ci] &lt;a href="https://github.com/NiklasRosenstein/flux-ci"&gt;https://github.com/NiklasRosenstein/flux-ci&lt;/a&gt;&lt;br/&gt;
[jenkins] &lt;a href="https://jenkins.io"&gt;https://jenkins.io&lt;/a&gt;&lt;br/&gt;
[gitea] &lt;a href="https://gitea.io"&gt;https://gitea.io&lt;/a&gt;&lt;br/&gt;
[golang] &lt;a href="https://www.golang.org"&gt;https://www.golang.org&lt;/a&gt;&lt;br/&gt;
[golang-dl] &lt;a href="https://golang.org/dl/"&gt;https://golang.org/dl/&lt;/a&gt;&lt;br/&gt;
[pelican] &lt;a href="https://www.getpelican.com"&gt;https://www.getpelican.com&lt;/a&gt;&lt;br/&gt;
[repository] &lt;a href="http://git.stefannaumann.de/snaums/mvoCI"&gt;http://git.stefannaumann.de/snaums/mvoCI&lt;/a&gt;&lt;/p&gt;</content><category term="Informatik"></category><category term="golang"></category><category term="continuous integration"></category><category term="my very own"></category><category term="mvoCI"></category><category term="CI"></category><category term="jenkins"></category><category term="pelican"></category><category term="git"></category><category term="building"></category></entry></feed>