Skip to content

Commit 3457391

Browse files
committed
Merge branch 'master' of https://github.com/gaia-pipeline/gaia into issue-30
2 parents 0f10cd8 + 17b7873 commit 3457391

File tree

5 files changed

+343
-31
lines changed

5 files changed

+343
-31
lines changed

README.rst

+38-13
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@
44

55
|build-status| |go-report| |go-doc| |apache2| |chat| |codecov|
66

7-
gaia is an open source automation platform which makes it easy and fun
8-
to build powerful pipelines in any programming language. Based on
9-
`HashiCorp's go-plugin`_ and `gRPC`_, gaia is efficient, fast, lightweight
10-
and developer friendly. Gaia is currently alpha! `Do not use it for mission
11-
critical jobs yet!`_
7+
Gaia is an open source automation platform which makes it easy and fun to build powerful pipelines in any programming language. Based on `HashiCorp's go-plugin`_ and `gRPC`_, gaia is efficient, fast, lightweight and developer friendly. Gaia is currently alpha! `Do not use it for mission critical jobs yet!`_
128

13-
Develop pipelines with the help of SDKs (currently only Go) and simply check-in your code into a git repository. Gaia automatically clones your code repository, compiles your code to a binary and executes it on-demand. All results are streamed back and formatted to a user-friendly graphical output.
9+
Develop powerful `pipelines <What is a pipeline?_>`_ with the help of `SDKs <Why do I need an SDK?_>`_ (currently only Go) and simply check-in your code into a git repository. Gaia automatically clones your code repository, compiles your code to a binary and executes it on-demand. All results are streamed back and formatted to a user-friendly graphical output.
1410

1511
Motivation
1612
==========
@@ -23,18 +19,20 @@ The majority of tech people are not motivated to take up this work and they are
2319

2420
One of the main reasons for this is the abstraction and poor execution of many automation tools. They come with their own configuration (`YAML`_ syntax) specification or limit the user to one specific programming language. Testing is nearly impossible because most automation tools lack the ability to mock services and subsystems. Even tiny things, for example parsing a JSON file, are sometimes really painful because external, outdated libraries were used and not included in the standard framework.
2521

26-
We believe it's time to remove all these abstractions and come back to our roots. Are you tired of writing endless lines of YAML-code? Are you sick of spending days forced to write in a language that does not suit you and is not fun at all? Do you enjoy programming in a language you like? Then gaia is for you.
22+
We believe it's time to remove all these abstractions and come back to our roots. Are you tired of writing endless lines of YAML-code? Are you sick of spending days forced to write in a language that does not suit you and is not fun at all? Do you enjoy programming in a language you like? Then Gaia is for you.
2723

2824
How does it work?
2925
=================
3026

3127
.. begin-architecture
3228
33-
Gaia is based on `HashiCorp's go-plugin`_. It's a plugin system that uses `gRPC`_ to communicate over HTTP2. HashiCorp developed this tool initially for `Packer`_ but it's now heavily used by `Terraform`_, `Nomad`_, and `Vault`_ too.
29+
Gaia is based on `HashiCorp's go-plugin`_. It's a plugin system that uses `gRPC`_ to communicate over `HTTP/2`_. HashiCorp developed this tool initially for `Packer`_ but it's now heavily used by `Terraform`_, `Nomad`_, and `Vault`_ too.
3430

35-
Pipelines can be written in any programming language (gRPC support is a prerequisite) and can be compiled locally or simply over the build system. Gaia clones the git repository and automatically builds the included pipeline.
31+
Plugins, which we named pipelines, are applications which can be written in any programming language as long as `gRPC`_ is supported. All functions, which we call Jobs, are exposed to Gaia and can form up a dependency graph which describes the order of execution.
3632

37-
After a pipeline has been started, all log output from the included jobs are returned back to gaia and displayed in a detailed overview with their final result status.
33+
Pipelines can be compiled locally or simply over the build system. Gaia clones the git repository and automatically builds the included pipeline. If a change (`git push`_) happened, Gaia will automatically rebuild the pipeline for you.
34+
35+
After a pipeline has been started, all log output are returned back to Gaia and displayed in a detailed overview with their final result status.
3836

3937
Gaia uses `boltDB` for storage. This makes the installation step super easy. No external database is currently required.
4038

@@ -134,10 +132,35 @@ Gaia will compile it and add it to it's store for later execution.
134132

135133
Please find a bit more sophisticated example in our `go-example repo`_.
136134

137-
Documentation
138-
=============
135+
Documentation and more
136+
======================
137+
138+
Please find the docs at https://docs.gaia-pipeline.io. We also have a tutorials section over there with examples and real use-case scenarios. For example, `Kubernetes deployment with vault integration`_.
139+
140+
Questions and Answers (Q&A)
141+
---------------------------
142+
143+
What problem solves **Gaia**?
144+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
145+
Literally every tool which were designed for automation, continuous integration (CI), and continuous deployment (CD) like Spinnaker, Jenkins, Gitlab CI/CD, TravisCI, CircleCI, Codeship, Bamboo and many more, introduced their own configuration format. Some of them don't even support *configuration/automation as code*. This works well for simple tasks like running a ``go install`` or ``mvn clean install`` but in the real world there is more to do.
146+
147+
Gaia is the first platform which does not limit the user and provides full support for almost all common programming languages without losing the features offered by todays CI/CD tools.
148+
149+
What is a **pipeline**?
150+
~~~~~~~~~~~~~~~~~~~~~~~
151+
A pipeline is a real application with at least one function (we call it Job). Every programming language can be used as long as gRPC is supported. We offer SDKs (currently only Go but others are already in development) to support the development.
152+
153+
What is a **job**?
154+
~~~~~~~~~~~~~~~~~~
155+
A job is a function, usually globally exposed to Gaia. Dependent on the dependency graph, Gaia will execute this function in a specific order.
156+
157+
Why do I need an **SDK**?
158+
~~~~~~~~~~~~~~~~~~~~~~~~~~
159+
The SDK implements the Gaia plugin gRPC interface and offers helper functions like serving the gRPC-Server. This helps you to focus on the real problem instead of doing the boring stuff.
139160

140-
Please find the docs at https://docs.gaia-pipeline.io. We also have a interesting tutorials section over there. For example, `Kubernetes deployment with vault integration`_.
161+
When do you support programming language **XYZ**?
162+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
163+
We are working hard to support as much programming languages as possible but our resources are limited and we are also mostly no experts in all programming languages. If you are willing to contribute, feel free to open an issue and start working.
141164

142165
Roadmap
143166
=======
@@ -182,6 +205,8 @@ If you have any questions feel free to contact us on `gitter`_.
182205
.. _`go-example repo`: https://github.com/gaia-pipeline/go-example
183206
.. _`gitter`: https://gitter.im/gaia-pipeline
184207
.. _`Kubernetes deployment with vault integration`: https://docs.gaia-pipeline.io/tutorials/kube-vault-deploy/
208+
.. _`git push`: https://git-scm.com/docs/git-push
209+
.. _`HTTP/2`: https://http2.github.io/
185210

186211
.. |build-status| image:: https://circleci.com/gh/gaia-pipeline/gaia/tree/master.svg?style=shield&circle-token=c0e15edfb08f8076076cbbb55558af6cfecb89b8
187212
:alt: Build Status

pipeline/build_golang_test.go

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package pipeline
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
67
"io/ioutil"
@@ -112,10 +113,10 @@ func TestExecuteBuildFailPipelineBuild(t *testing.T) {
112113
}()
113114
gaia.Cfg = new(gaia.Config)
114115
gaia.Cfg.HomePath = tmp
115-
var logOutput strings.Builder
116+
buf := new(bytes.Buffer)
116117
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
117118
Level: hclog.Trace,
118-
Output: &logOutput,
119+
Output: buf,
119120
Name: "Gaia",
120121
})
121122
b := new(BuildPipelineGolang)
@@ -142,10 +143,10 @@ func TestExecuteBuildContextTimeout(t *testing.T) {
142143
gaia.Cfg = new(gaia.Config)
143144
gaia.Cfg.HomePath = tmp
144145
// Initialize shared logger
145-
var logOutput strings.Builder
146+
buf := new(bytes.Buffer)
146147
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
147148
Level: hclog.Trace,
148-
Output: &logOutput,
149+
Output: buf,
149150
Name: "Gaia",
150151
})
151152
b := new(BuildPipelineGolang)
@@ -164,10 +165,10 @@ func TestExecuteBuildBinaryNotFoundError(t *testing.T) {
164165
gaia.Cfg = new(gaia.Config)
165166
gaia.Cfg.HomePath = tmp
166167
// Initialize shared logger
167-
var logOutput strings.Builder
168+
buf := new(bytes.Buffer)
168169
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
169170
Level: hclog.Trace,
170-
Output: &logOutput,
171+
Output: buf,
171172
Name: "Gaia",
172173
})
173174
currentPath := os.Getenv("PATH")
@@ -189,10 +190,10 @@ func TestCopyBinary(t *testing.T) {
189190
gaia.Cfg = new(gaia.Config)
190191
gaia.Cfg.HomePath = tmp
191192
// Initialize shared logger
192-
var logOutput strings.Builder
193+
buf := new(bytes.Buffer)
193194
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
194195
Level: hclog.Trace,
195-
Output: &logOutput,
196+
Output: buf,
196197
Name: "Gaia",
197198
})
198199
b := new(BuildPipelineGolang)
@@ -224,10 +225,10 @@ func TestCopyBinarySrcDoesNotExist(t *testing.T) {
224225
gaia.Cfg = new(gaia.Config)
225226
gaia.Cfg.HomePath = tmp
226227
// Initialize shared logger
227-
var logOutput strings.Builder
228+
buf := new(bytes.Buffer)
228229
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
229230
Level: hclog.Trace,
230-
Output: &logOutput,
231+
Output: buf,
231232
Name: "Gaia",
232233
})
233234
b := new(BuildPipelineGolang)

pipeline/git_test.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package pipeline
22

33
import (
4+
"bytes"
45
"os"
56
"strconv"
67
"strings"
@@ -28,10 +29,10 @@ func TestUpdateAllPipelinesRepositoryNotFound(t *testing.T) {
2829
gaia.Cfg = new(gaia.Config)
2930
gaia.Cfg.HomePath = tmp
3031
// Initialize shared logger
31-
var b strings.Builder
32+
b := new(bytes.Buffer)
3233
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
3334
Level: hclog.Trace,
34-
Output: &b,
35+
Output: b,
3536
Name: "Gaia",
3637
})
3738

@@ -49,10 +50,10 @@ func TestUpdateAllPipelinesAlreadyUpToDate(t *testing.T) {
4950
gaia.Cfg = new(gaia.Config)
5051
gaia.Cfg.HomePath = "tmp"
5152
// Initialize shared logger
52-
var b strings.Builder
53+
b := new(bytes.Buffer)
5354
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
5455
Level: hclog.Trace,
55-
Output: &b,
56+
Output: b,
5657
Name: "Gaia",
5758
})
5859
repo := &gaia.GitRepo{
@@ -82,10 +83,10 @@ func TestUpdateAllPipelinesAlreadyUpToDateWithMoreThanOnePipeline(t *testing.T)
8283
gaia.Cfg = new(gaia.Config)
8384
gaia.Cfg.HomePath = "tmp"
8485
// Initialize shared logger
85-
var b strings.Builder
86+
b := new(bytes.Buffer)
8687
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
8788
Level: hclog.Trace,
88-
Output: &b,
89+
Output: b,
8990
Name: "Gaia",
9091
})
9192
repo := &gaia.GitRepo{
@@ -124,10 +125,10 @@ func TestUpdateAllPipelinesHundredPipelines(t *testing.T) {
124125
gaia.Cfg = new(gaia.Config)
125126
gaia.Cfg.HomePath = "tmp"
126127
// Initialize shared logger
127-
var b strings.Builder
128+
b := new(bytes.Buffer)
128129
gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{
129130
Level: hclog.Trace,
130-
Output: &b,
131+
Output: b,
131132
Name: "Gaia",
132133
})
133134
repo := &gaia.GitRepo{

security/tls.go

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package security
2+
3+
import (
4+
"crypto/rand"
5+
"crypto/rsa"
6+
"crypto/tls"
7+
"crypto/x509"
8+
"crypto/x509/pkix"
9+
"encoding/pem"
10+
"io/ioutil"
11+
"math/big"
12+
"os"
13+
"path/filepath"
14+
"time"
15+
16+
"github.com/gaia-pipeline/gaia"
17+
)
18+
19+
const (
20+
rsaBits = 2048
21+
maxValidCA = 17520 // 2 years
22+
maxValidCERT = 48 // 48 hours
23+
orgName = "gaia-pipeline"
24+
orgDNS = "gaia-pipeline.io"
25+
26+
// CA key name
27+
certName = "ca.crt"
28+
keyName = "ca.key"
29+
)
30+
31+
// GenerateCA generates the CA and puts it into the data folder.
32+
// The CA will be always overwritten on startup.
33+
func GenerateCA() error {
34+
// Cleanup old certs if existing.
35+
// We ignore the error here cause files might be non existend.
36+
caCertPath := filepath.Join(gaia.Cfg.DataPath, certName)
37+
caKeyPath := filepath.Join(gaia.Cfg.DataPath, keyName)
38+
cleanupCerts(caCertPath, caKeyPath)
39+
40+
// Set time range for cert validation
41+
notBefore := time.Now()
42+
notAfter := notBefore.Add(time.Hour * maxValidCA)
43+
44+
// Generate serial number
45+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
46+
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
47+
if err != nil {
48+
return err
49+
}
50+
51+
// Generate CA template
52+
template := &x509.Certificate{
53+
SerialNumber: serialNumber,
54+
Subject: pkix.Name{
55+
Organization: []string{orgName},
56+
},
57+
NotBefore: notBefore,
58+
NotAfter: notAfter,
59+
60+
IsCA: true,
61+
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
62+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
63+
BasicConstraintsValid: true,
64+
DNSNames: []string{orgDNS},
65+
}
66+
67+
// Generate the key
68+
key, err := rsa.GenerateKey(rand.Reader, rsaBits)
69+
if err != nil {
70+
return err
71+
}
72+
73+
// Create certificate authority
74+
derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
75+
if err != nil {
76+
return err
77+
}
78+
79+
// Write out the ca.crt file
80+
certOut, err := os.Create(caCertPath)
81+
if err != nil {
82+
return err
83+
}
84+
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
85+
certOut.Close()
86+
87+
// Write out the ca.key file
88+
keyOut, err := os.OpenFile(caKeyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
89+
if err != nil {
90+
return err
91+
}
92+
pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
93+
keyOut.Close()
94+
95+
return nil
96+
}
97+
98+
// createSignedCert creates a new key pair which is signed by the CA.
99+
func createSignedCert() (string, string, error) {
100+
caCertPath := filepath.Join(gaia.Cfg.DataPath, "ca.crt")
101+
caKeyPath := filepath.Join(gaia.Cfg.DataPath, "ca.key")
102+
103+
// Load CA plain
104+
caPlain, err := tls.LoadX509KeyPair(caCertPath, caKeyPath)
105+
if err != nil {
106+
return "", "", err
107+
}
108+
109+
// Parse certificate
110+
ca, err := x509.ParseCertificate(caPlain.Certificate[0])
111+
if err != nil {
112+
return "", "", err
113+
}
114+
115+
// Generate serial number
116+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
117+
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
118+
if err != nil {
119+
return "", "", err
120+
}
121+
122+
// Set time range for cert validation
123+
notBefore := time.Now()
124+
notAfter := notBefore.Add(time.Hour * maxValidCERT)
125+
126+
// Prepare certificate
127+
cert := &x509.Certificate{
128+
SerialNumber: serialNumber,
129+
Subject: pkix.Name{
130+
Organization: []string{orgName},
131+
},
132+
NotBefore: notBefore,
133+
NotAfter: notAfter,
134+
SubjectKeyId: []byte{1, 2, 3, 4, 6},
135+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
136+
KeyUsage: x509.KeyUsageDigitalSignature,
137+
DNSNames: []string{orgDNS},
138+
}
139+
priv, _ := rsa.GenerateKey(rand.Reader, rsaBits)
140+
pub := &priv.PublicKey
141+
142+
// Sign the certificate
143+
certSigned, err := x509.CreateCertificate(rand.Reader, cert, ca, pub, caPlain.PrivateKey)
144+
145+
// Public key
146+
certOut, err := ioutil.TempFile("", "crt")
147+
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certSigned})
148+
certOut.Close()
149+
150+
// Private key
151+
keyOut, err := ioutil.TempFile("", "key")
152+
pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
153+
keyOut.Close()
154+
155+
return certOut.Name(), keyOut.Name(), nil
156+
}
157+
158+
// cleanupCerts removes certificates at the given path.
159+
func cleanupCerts(crt, key string) error {
160+
if err := os.Remove(crt); err != nil {
161+
return err
162+
}
163+
return os.Remove(key)
164+
}

0 commit comments

Comments
 (0)