Added seed code for caas-helm.
[ta/caas-helm.git] / src / chart-repo-handler / main.go
1 // Copyright 2019 Nokia
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package main
16
17 import (
18   "crypto/tls"
19   "log"
20   "net/http"
21   "pkg/api"
22   "pkg/config"
23   "pkg/repo"
24   "github.com/kelseyhightower/envconfig"
25   "github.com/ncw/swift"
26   "os"
27   "os/signal"
28   "syscall"
29   "strconv"
30   "time"
31   "errors"
32   "crypto/x509"
33   "io/ioutil"
34 )
35
36 var (
37   chartRepo *http.Server
38 )
39
40 const (
41   regenRetryCounter = 10
42 )
43
44 func main() {
45   var envConfig config.EnvConfig
46   err := envconfig.Process("chartrepohandler", &envConfig)
47   if err != nil {
48     log.Fatal(err.Error())
49     }
50
51   swiftCon := connectSwift(envConfig)
52   log.Println("Chart repo handler v0.9 started up.")
53   log.Printf("Config: %s\n", envConfig.ToString())
54   log.Println("Regenerating index for:", envConfig.IndexPath)
55   if err := regenerateIndexYaml(envConfig, &swiftCon); err != nil {
56     log.Println(err.Error())
57     os.Exit(-1)
58     }
59   startHttpServer(envConfig, &swiftCon)
60   signalChan := make(chan os.Signal, 1)
61   signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
62   for {
63     select {
64       case <-signalChan:
65         log.Println("Shutdown signal received, exiting...")
66         if (chartRepo != nil) {
67           chartRepo.Close()
68           }
69         os.Exit(0)
70     }
71   }
72 }
73
74 func connectSwift(envConfig config.EnvConfig) swift.Connection {
75   swiftCon := swift.Connection{
76     UserName:   envConfig.AuthUser,
77     ApiKey:     envConfig.AuthKey,
78     AuthUrl:    envConfig.AuthUrl,
79     }
80   if envConfig.TlsCaPath != "" {
81     log.Printf("INFO: TlsCaPath is presented: Trying to enforce TLS Authentication on swift backend using the server certs")
82     file, err := ioutil.ReadFile(envConfig.TlsCaPath)
83     if err != nil {
84       log.Fatal(err)
85       log.Printf("Wrong or missing value in paramteter: TlsCaPath")
86       os.Exit(-1)
87       }
88     certPool := x509.NewCertPool()
89     ok := certPool.AppendCertsFromPEM([]byte(file))
90     if !ok {
91       log.Fatal("Corrupt CACert file")
92       os.Exit(-1)
93       }
94     cert, err := tls.LoadX509KeyPair(envConfig.TlsCertPath, envConfig.TlsKeyPath)
95     if err != nil {
96       log.Fatal(err)
97       log.Printf("Wrong or missing value in paramteter: TlsCertPath or TlsKeyPath")
98       os.Exit(-1)
99       }
100     swiftCon.Transport = &http.Transport{
101       TLSClientConfig: &tls.Config{
102         RootCAs: certPool,
103         Certificates: []tls.Certificate{cert}, 
104         },
105       }
106     }
107   return swiftCon
108 }
109
110 func regenerateIndexYaml(envConfig config.EnvConfig, swiftConn *swift.Connection) error {
111   var err error
112   for i := 0; i <= regenRetryCounter; i++ {
113     err = repo.Index(swiftConn, envConfig.Container, envConfig.RepoUrl+":"+envConfig.ListenOnPort, envConfig.IndexPath, "/index.yaml")
114     if err != nil {
115       log.Println("INFO: Regenerating index.yaml in Swift try no.: " + strconv.Itoa(i) + " was unsuccessful at: " + swiftConn.AuthUrl +
116                   " with error:" + err.Error())
117       time.Sleep(10 * time.Second)
118       continue
119     } else {
120       return nil
121     }
122   }
123   return errors.New("ERROR: Swift is not responsive, giving-up regeneration!")
124 }
125
126 func startHttpServer(envConfig config.EnvConfig, swiftConn *swift.Connection) {
127   router := api.NewRouter(swiftConn, envConfig)
128   var tlsCfg *tls.Config
129   if envConfig.TlsCertPath != "" && envConfig.TlsKeyPath != "" {
130     log.Println("TLS used")
131     tlsCfg = &tls.Config{
132       MinVersion:               tls.VersionTLS12,
133       CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
134       PreferServerCipherSuites: true,
135       CipherSuites: []uint16{
136         tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
137         tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
138         tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
139         tls.TLS_RSA_WITH_AES_256_CBC_SHA,
140       },
141     }
142   } else {
143     tlsCfg = &tls.Config{}
144   }
145   chartRepo = &http.Server{
146     Addr:         envConfig.ListenOnIP + ":" + envConfig.ListenOnPort,
147     Handler:      router,
148     TLSConfig:    tlsCfg,
149     TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
150   }
151   go func() {
152     if chartRepo.TLSConfig != nil {
153       log.Fatal(chartRepo.ListenAndServeTLS(envConfig.TlsCertPath, envConfig.TlsKeyPath))
154     } else {
155       log.Fatal(chartRepo.ListenAndServe())
156     }
157   }()
158 }
159