From 9b1b1820a28605162e93fe64ad48501e37d6d453 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 18:04:18 +0200 Subject: [PATCH 1/3] Update module github.com/prometheus/common to v0.54.0 (#34) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 9 ++++----- go.sum | 36 ++++++++---------------------------- 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index dd715912..ab7f3b38 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0 github.com/prometheus/client_golang v1.19.1 - github.com/prometheus/common v0.53.0 + github.com/prometheus/common v0.54.0 github.com/sirupsen/logrus v1.9.3 k8s.io/api v0.29.5 k8s.io/apimachinery v0.29.5 @@ -49,22 +49,21 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/procfs v0.13.0 // indirect github.com/spf13/pflag v1.0.5 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect golang.org/x/net v0.25.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/oauth2 v0.19.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/term v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.34.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 3833f715..af050a41 100644 --- a/go.sum +++ b/go.sum @@ -30,13 +30,10 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -93,10 +90,10 @@ github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0 h github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0/go.mod h1:wAR5JopumPtAZnu0Cjv2PSqV4p4QB09LMhc6fZZTXuA= github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= -github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= -github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= +github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o= github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -115,7 +112,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -125,46 +121,35 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -173,7 +158,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -182,12 +166,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= +google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From f273827c964880bd9f698db19508a716e7e6c814 Mon Sep 17 00:00:00 2001 From: Zirko <64951262+QuantumEnigmaa@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:16:19 +0200 Subject: [PATCH 2/3] add mimir support (#22) * add mimir support * update dockerfile to use binary needed in the code * add imports * use capital letters for function names * fix minor errors * apply suggestions * solved last import issue * removed unused function * sort imports order * small enhancements * applying suggestions * fixes * refactor code * add golintci exclusions * change auth secret const name * remove leftovers debug code * update username for ingress secret * format htpasswd * debug * fix remotewrite url * remove debug code * remove finalizers from secrets and configmaps * Update Dockerfile Co-authored-by: Quentin Bisson * Apply suggestions from code review Co-authored-by: Quentin Bisson * small fix for the linter * only reconcile mimir config for the mc * code refactoring * Delete old secrets when creating basic-auth one * get rid of htpasswd * use in-line exclusions instead of global ones for gosec * improvements * revert back to distroless image * simplify secret deletion * apply suggestions * added comment for explaining lint exclusions * update logger --------- Co-authored-by: Quentin Bisson --- CHANGELOG.md | 5 + go.mod | 1 + go.sum | 2 + .../cluster_monitoring_controller.go | 30 +++- main.go | 8 + pkg/common/password/manager.go | 13 ++ pkg/common/secret/utils.go | 42 +++++ pkg/monitoring/mimir/service.go | 163 ++++++++++++++++++ pkg/monitoring/prometheusagent/secret.go | 73 +++++--- pkg/monitoring/prometheusagent/service.go | 25 +-- pkg/monitoring/prometheusagent/types.go | 4 +- 11 files changed, 320 insertions(+), 46 deletions(-) create mode 100644 pkg/common/secret/utils.go create mode 100644 pkg/monitoring/mimir/service.go diff --git a/CHANGELOG.md b/CHANGELOG.md index bafe7a13..403acfbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Add + +- Add support for mimir in remoteWrite secret creation. +- Add mimir ingress secret for basic auth creation. + ## [0.0.4] - 2024-05-28 ### Changed diff --git a/go.mod b/go.mod index ab7f3b38..95a3f432 100644 --- a/go.mod +++ b/go.mod @@ -54,6 +54,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.23.0 golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/oauth2 v0.19.0 // indirect diff --git a/go.sum b/go.sum index af050a41..5f3d077f 100644 --- a/go.sum +++ b/go.sum @@ -121,6 +121,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= diff --git a/internal/controller/cluster_monitoring_controller.go b/internal/controller/cluster_monitoring_controller.go index d2685361..439b9b97 100644 --- a/internal/controller/cluster_monitoring_controller.go +++ b/internal/controller/cluster_monitoring_controller.go @@ -32,6 +32,7 @@ import ( "github.com/giantswarm/observability-operator/pkg/common" "github.com/giantswarm/observability-operator/pkg/monitoring" "github.com/giantswarm/observability-operator/pkg/monitoring/heartbeat" + "github.com/giantswarm/observability-operator/pkg/monitoring/mimir" "github.com/giantswarm/observability-operator/pkg/monitoring/prometheusagent" ) @@ -44,6 +45,8 @@ type ClusterMonitoringReconciler struct { prometheusagent.PrometheusAgentService // HeartbeatRepository is the repository for managing heartbeats. heartbeat.HeartbeatRepository + // MimirService is the service for managing mimir configuration. + mimir.MimirService // MonitoringEnabled defines whether monitoring is enabled at the installation level. MonitoringEnabled bool } @@ -65,8 +68,6 @@ func (r *ClusterMonitoringReconciler) SetupWithManager(mgr ctrl.Manager) error { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.17.0/pkg/reconcile func (r *ClusterMonitoringReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - // Fetch the Cluster instance. cluster := &clusterv1.Cluster{} if err := r.Client.Get(ctx, req.NamespacedName, cluster); err != nil { @@ -80,6 +81,11 @@ func (r *ClusterMonitoringReconciler) Reconcile(ctx context.Context, req ctrl.Re return ctrl.Result{}, errors.WithStack(err) } + // Linting is disabled for the 2 following lines as otherwise it fails with the following error: + // "should not use built-in type string as key for value" + logger := log.FromContext(ctx).WithValues("cluster", cluster.Name).WithValues("installation", r.ManagementCluster.Name) // nolint + ctx = log.IntoContext(ctx, logger) + if !r.MonitoringEnabled { logger.Info("Monitoring is disabled at the installation level") return ctrl.Result{}, nil @@ -87,18 +93,18 @@ func (r *ClusterMonitoringReconciler) Reconcile(ctx context.Context, req ctrl.Re // Handle deletion reconciliation loop. if !cluster.ObjectMeta.DeletionTimestamp.IsZero() { - logger.Info("Handling deletion for Cluster", "cluster", cluster.Name) + logger.Info("Handling deletion for Cluster") return r.reconcileDelete(ctx, cluster) } - logger.Info("Reconciling Cluster", "cluster", cluster.Name) + logger.Info("Reconciling Cluster") // Handle normal reconciliation loop. return r.reconcile(ctx, cluster) } // reconcile handles cluster reconciliation. func (r *ClusterMonitoringReconciler) reconcile(ctx context.Context, cluster *clusterv1.Cluster) (ctrl.Result, error) { - logger := log.FromContext(ctx).WithValues("cluster", cluster.Name) + logger := log.FromContext(ctx) // Add finalizer first if not set to avoid the race condition between init and delete. // Note: Finalizers in general can only be added when the deletionTimestamp is not set. @@ -120,6 +126,12 @@ func (r *ClusterMonitoringReconciler) reconcile(ctx context.Context, cluster *cl logger.Error(err, "failed to create or update heartbeat") return ctrl.Result{RequeueAfter: 5 * time.Minute}, errors.WithStack(err) } + + err = r.MimirService.ConfigureMimir(ctx) + if err != nil { + logger.Error(err, "failed to configure mimir") + return ctrl.Result{RequeueAfter: 5 * time.Minute}, errors.WithStack(err) + } } // Create or update PrometheusAgent remote write configuration. @@ -134,7 +146,7 @@ func (r *ClusterMonitoringReconciler) reconcile(ctx context.Context, cluster *cl // reconcileDelete handles cluster deletion. func (r *ClusterMonitoringReconciler) reconcileDelete(ctx context.Context, cluster *clusterv1.Cluster) (reconcile.Result, error) { - logger := log.FromContext(ctx).WithValues("cluster", cluster.Name) + logger := log.FromContext(ctx) if controllerutil.ContainsFinalizer(cluster, monitoring.MonitoringFinalizer) { if cluster.Name == r.ManagementCluster.Name { err := r.HeartbeatRepository.Delete(ctx) @@ -142,6 +154,12 @@ func (r *ClusterMonitoringReconciler) reconcileDelete(ctx context.Context, clust logger.Error(err, "failed to delete heartbeat") return ctrl.Result{RequeueAfter: 5 * time.Minute}, errors.WithStack(err) } + + err = r.MimirService.DeleteMimirSecrets(ctx) + if err != nil { + logger.Error(err, "failed to delete mimir ingress secret") + return ctrl.Result{RequeueAfter: 5 * time.Minute}, errors.WithStack(err) + } } err := r.PrometheusAgentService.DeleteRemoteWriteConfiguration(ctx, cluster) diff --git a/main.go b/main.go index 1d40ecd8..06de81aa 100644 --- a/main.go +++ b/main.go @@ -42,6 +42,7 @@ import ( "github.com/giantswarm/observability-operator/pkg/common/organization" "github.com/giantswarm/observability-operator/pkg/common/password" "github.com/giantswarm/observability-operator/pkg/monitoring/heartbeat" + "github.com/giantswarm/observability-operator/pkg/monitoring/mimir" "github.com/giantswarm/observability-operator/pkg/monitoring/prometheusagent" //+kubebuilder:scaffold:imports ) @@ -195,11 +196,18 @@ func main() { PrometheusVersion: prometheusVersion, } + mimirService := mimir.MimirService{ + Client: mgr.GetClient(), + PasswordManager: password.SimpleManager{}, + ManagementCluster: managementCluster, + } + if err = (&controller.ClusterMonitoringReconciler{ Client: mgr.GetClient(), ManagementCluster: managementCluster, HeartbeatRepository: heartbeatRepository, PrometheusAgentService: prometheusAgentService, + MimirService: mimirService, MonitoringEnabled: monitoringEnabled, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Cluster") diff --git a/pkg/common/password/manager.go b/pkg/common/password/manager.go index 80c2726b..c4704bef 100644 --- a/pkg/common/password/manager.go +++ b/pkg/common/password/manager.go @@ -3,10 +3,14 @@ package password import ( "crypto/rand" "encoding/hex" + "fmt" + + "golang.org/x/crypto/bcrypt" ) type Manager interface { GeneratePassword(length int) (string, error) + GenerateHtpasswd(username string, password string) (string, error) } type SimpleManager struct { @@ -19,3 +23,12 @@ func (m SimpleManager) GeneratePassword(length int) (string, error) { } return hex.EncodeToString(bytes), nil } + +func (m SimpleManager) GenerateHtpasswd(username, password string) (string, error) { + encryptedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return "", err + } + formattedHtpasswd := fmt.Sprintf("%s:%s", username, string(encryptedPassword)) + return formattedHtpasswd, nil +} diff --git a/pkg/common/secret/utils.go b/pkg/common/secret/utils.go new file mode 100644 index 00000000..e9790e35 --- /dev/null +++ b/pkg/common/secret/utils.go @@ -0,0 +1,42 @@ +package secret + +import ( + "context" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func GenerateGenericSecret(secretName string, secretNamespace string, + key string, value string) *corev1.Secret { + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + Namespace: secretNamespace, + }, + Data: map[string][]byte{ + key: []byte(value), + }, + Type: "Opaque", + } + + return secret +} + +func DeleteSecret(secretName string, secretNamespace string, + ctx context.Context, providedClient client.Client) error { + current := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + Namespace: secretNamespace, + }, + } + + if err := providedClient.Delete(ctx, current); client.IgnoreNotFound(err) != nil { + return errors.WithStack(err) + } + + return nil +} diff --git a/pkg/monitoring/mimir/service.go b/pkg/monitoring/mimir/service.go new file mode 100644 index 00000000..1160726d --- /dev/null +++ b/pkg/monitoring/mimir/service.go @@ -0,0 +1,163 @@ +package mimir + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/giantswarm/observability-operator/pkg/common" + "github.com/giantswarm/observability-operator/pkg/common/password" + "github.com/giantswarm/observability-operator/pkg/common/secret" + "github.com/giantswarm/observability-operator/pkg/monitoring/prometheusagent" +) + +const ( + ingressAuthSecretName = "mimir-gateway-ingress-auth" // #nosec G101 + mimirApiKey = "mimir-basic-auth" // #nosec G101 + mimirNamespace = "mimir" +) + +type MimirService struct { + client.Client + PasswordManager password.Manager + common.ManagementCluster +} + +// ConfigureMimir configures the ingress and its authentication (basic auth) +// to allow prometheus agents to send their data to Mimir +func (ms *MimirService) ConfigureMimir(ctx context.Context) error { + logger := log.FromContext(ctx) + logger.Info("configuring mimir ingress") + + err := ms.CreateApiKey(ctx, logger) + if err != nil { + logger.Error(err, "failed to create mimir auth secret") + return errors.WithStack(err) + } + + err = ms.CreateIngressAuthenticationSecret(ctx, logger) + if err != nil { + logger.Error(err, "failed to create mimir ingress secret") + return errors.WithStack(err) + } + + logger.Info("configured mimir ingress") + + return nil +} + +func (ms *MimirService) CreateApiKey(ctx context.Context, logger logr.Logger) error { + objectKey := client.ObjectKey{ + Name: mimirApiKey, + Namespace: mimirNamespace, + } + + current := &corev1.Secret{} + err := ms.Client.Get(ctx, objectKey, current) + if apierrors.IsNotFound(err) { + // First all secrets using the password from the mimirApiKey secret are deleted + // to ensure that they won't use an outdated password. + logger.Info("Deleting old secrets") + + err := secret.DeleteSecret(ingressAuthSecretName, mimirNamespace, ctx, ms.Client) + if err != nil { + return errors.WithStack(err) + } + + clusterList := &clusterv1.ClusterList{} + err = ms.Client.List(ctx, clusterList) + if err != nil { + return errors.WithStack(err) + } + + for _, cluster := range clusterList.Items { + secretName := prometheusagent.GetPrometheusAgentRemoteWriteSecretName(&cluster) // #nosec G601 + err = secret.DeleteSecret(secretName, cluster.Namespace, ctx, ms.Client) + if err != nil { + return errors.WithStack(err) + } + } + + // Once all secrets are deleted,the mimirApiKey one may be created. + logger.Info("Building auth secret") + + password, err := ms.PasswordManager.GeneratePassword(32) + if err != nil { + return errors.WithStack(err) + } + + secret := secret.GenerateGenericSecret( + mimirApiKey, mimirNamespace, "credentials", password) + + err = ms.Client.Create(ctx, secret) + if err != nil { + return errors.WithStack(err) + } + + logger.Info("Auth secret successfully created") + + return nil + } else if err != nil { + return errors.WithStack(err) + } + + return nil +} + +func (ms *MimirService) CreateIngressAuthenticationSecret(ctx context.Context, logger logr.Logger) error { + objectKey := client.ObjectKey{ + Name: ingressAuthSecretName, + Namespace: mimirNamespace, + } + + current := &corev1.Secret{} + err := ms.Client.Get(ctx, objectKey, current) + if apierrors.IsNotFound(err) { + logger.Info("building ingress secret") + + password, err := prometheusagent.GetMimirIngressPassword(ctx) + if err != nil { + return errors.WithStack(err) + } + + htpasswd, err := ms.PasswordManager.GenerateHtpasswd(ms.ManagementCluster.Name, password) + if err != nil { + return errors.WithStack(err) + } + + secret := secret.GenerateGenericSecret(ingressAuthSecretName, mimirNamespace, "auth", htpasswd) + + err = ms.Client.Create(ctx, secret) + if err != nil { + return errors.WithStack(err) + } + + logger.Info("ingress secret successfully created") + + return nil + } else if err != nil { + return errors.WithStack(err) + } + + return nil +} + +func (ms *MimirService) DeleteMimirSecrets(ctx context.Context) error { + err := secret.DeleteSecret(ingressAuthSecretName, mimirNamespace, ctx, ms.Client) + if err != nil { + return errors.WithStack(err) + } + + err = secret.DeleteSecret(mimirApiKey, mimirNamespace, ctx, ms.Client) + if err != nil { + return errors.WithStack(err) + } + + return nil +} diff --git a/pkg/monitoring/prometheusagent/secret.go b/pkg/monitoring/prometheusagent/secret.go index 9b44abfe..ac95d7d8 100644 --- a/pkg/monitoring/prometheusagent/secret.go +++ b/pkg/monitoring/prometheusagent/secret.go @@ -1,6 +1,7 @@ package prometheusagent import ( + "context" "fmt" "github.com/pkg/errors" @@ -8,18 +9,55 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/yaml" ) -func getPrometheusAgentRemoteWriteSecretName(cluster *clusterv1.Cluster) string { +const ( + mimirApiKey = "mimir-basic-auth" // #nosec G101 + mimirNamespace = "mimir" +) + +func GetMimirIngressPassword(ctx context.Context) (string, error) { + cfg, err := config.GetConfig() + if err != nil { + return "", err + } + + c, err := client.New(cfg, client.Options{}) + if err != nil { + return "", err + } + + secret := &corev1.Secret{} + + err = c.Get(ctx, client.ObjectKey{ + Name: mimirApiKey, + Namespace: mimirNamespace, + }, secret) + if err != nil { + return "", err + } + + mimirPassword, err := readMimirAuthPasswordFromSecret(*secret) + + return mimirPassword, err +} + +func GetPrometheusAgentRemoteWriteSecretName(cluster *clusterv1.Cluster) string { return fmt.Sprintf("%s-remote-write-secret", cluster.Name) } // buildRemoteWriteSecret builds the secret that contains the remote write configuration for the Prometheus agent. -func (pas PrometheusAgentService) buildRemoteWriteSecret( - cluster *clusterv1.Cluster, password string) (*corev1.Secret, error) { +func (pas PrometheusAgentService) buildRemoteWriteSecret(ctx context.Context, + cluster *clusterv1.Cluster) (*corev1.Secret, error) { + url := fmt.Sprintf(remoteWriteEndpointTemplateURL, pas.ManagementCluster.BaseDomain) + password, err := GetMimirIngressPassword(ctx) + if err != nil { + return nil, errors.WithStack(err) + } - url := fmt.Sprintf(remoteWriteEndpointTemplateURL, pas.ManagementCluster.BaseDomain, cluster.Name) config := RemoteWriteConfig{ PrometheusAgentConfig: &PrometheusAgentConfig{ RemoteWrite: []*RemoteWrite{ @@ -39,7 +77,7 @@ func (pas PrometheusAgentService) buildRemoteWriteSecret( }, }, }, - Username: cluster.Name, + Username: pas.ManagementCluster.Name, Password: password, }, }, @@ -53,7 +91,7 @@ func (pas PrometheusAgentService) buildRemoteWriteSecret( return &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: getPrometheusAgentRemoteWriteSecretName(cluster), + Name: GetPrometheusAgentRemoteWriteSecretName(cluster), Namespace: cluster.Namespace, }, Data: map[string][]byte{ @@ -63,21 +101,16 @@ func (pas PrometheusAgentService) buildRemoteWriteSecret( }, nil } -func readRemoteWritePasswordFromSecret(secret corev1.Secret) (string, error) { - remoteWriteConfig := RemoteWriteConfig{} - err := yaml.Unmarshal(secret.Data["values"], &remoteWriteConfig) - if err != nil { - return "", errors.WithStack(err) - } +func readMimirAuthPasswordFromSecret(secret corev1.Secret) (string, error) { + if credentials, ok := secret.Data["credentials"]; !ok { + return "", errors.New("credentials key not found in secret") + } else { + var secretData string - for _, rw := range remoteWriteConfig.PrometheusAgentConfig.RemoteWrite { - // We read the secret from the remote write configuration named `prometheus-meta-operator` only - // as this secret is generated per cluster. - // This will eventually be taken care of by the multi-tenancy contoller - if rw.Name == remoteWriteName { - return rw.Password, nil + err := yaml.Unmarshal(credentials, &secretData) + if err != nil { + return "", errors.WithStack(err) } + return secretData, nil } - - return "", errors.New("remote write password not found in secret") } diff --git a/pkg/monitoring/prometheusagent/service.go b/pkg/monitoring/prometheusagent/service.go index b0af1d3a..523b602a 100644 --- a/pkg/monitoring/prometheusagent/service.go +++ b/pkg/monitoring/prometheusagent/service.go @@ -98,7 +98,7 @@ func (pas PrometheusAgentService) createOrUpdateConfigMap(ctx context.Context, func (pas PrometheusAgentService) createOrUpdateSecret(ctx context.Context, cluster *clusterv1.Cluster, logger logr.Logger) error { objectKey := client.ObjectKey{ - Name: getPrometheusAgentRemoteWriteSecretName(cluster), + Name: GetPrometheusAgentRemoteWriteSecretName(cluster), Namespace: cluster.GetNamespace(), } @@ -106,18 +106,14 @@ func (pas PrometheusAgentService) createOrUpdateSecret(ctx context.Context, // Get the current secret if it exists. err := pas.Client.Get(ctx, objectKey, current) if apierrors.IsNotFound(err) { - logger.Info("generating password for the prometheus agent") - password, err := pas.PasswordManager.GeneratePassword(32) + logger.Info("generating remote write secret for the prometheus agent") + secret, err := pas.buildRemoteWriteSecret(ctx, cluster) if err != nil { - logger.Error(err, "failed to generate the prometheus agent password") + logger.Error(err, "failed to generate the remote write secret for the prometheus agent") return errors.WithStack(err) } - logger.Info("generated password for the prometheus agent") + logger.Info("generated the remote write secret for the prometheus agent") - secret, err := pas.buildRemoteWriteSecret(cluster, password) - if err != nil { - return errors.WithStack(err) - } err = pas.Client.Create(ctx, secret) if err != nil { return errors.WithStack(err) @@ -127,14 +123,7 @@ func (pas PrometheusAgentService) createOrUpdateSecret(ctx context.Context, return errors.WithStack(err) } - // As it takes a long time to apply the new password to the agent due to a built-in delay in the app-platform, - // we keep the already generated remote write password. - password, err := readRemoteWritePasswordFromSecret(*current) - if err != nil { - return errors.WithStack(err) - } - - desired, err := pas.buildRemoteWriteSecret(cluster, password) + desired, err := pas.buildRemoteWriteSecret(ctx, cluster) if err != nil { return errors.WithStack(err) } @@ -195,7 +184,7 @@ func (pas PrometheusAgentService) deleteConfigMap(ctx context.Context, cluster * func (pas PrometheusAgentService) deleteSecret(ctx context.Context, cluster *clusterv1.Cluster) error { objectKey := client.ObjectKey{ - Name: getPrometheusAgentRemoteWriteSecretName(cluster), + Name: GetPrometheusAgentRemoteWriteSecretName(cluster), Namespace: cluster.GetNamespace(), } secret := &corev1.Secret{} diff --git a/pkg/monitoring/prometheusagent/types.go b/pkg/monitoring/prometheusagent/types.go index f77746af..cd65ed60 100644 --- a/pkg/monitoring/prometheusagent/types.go +++ b/pkg/monitoring/prometheusagent/types.go @@ -13,8 +13,8 @@ const ( // servicePriorityLabel is the label used to determine the priority of a service. servicePriorityLabel string = "giantswarm.io/service-priority" - remoteWriteEndpointTemplateURL = "https://prometheus.%s/%s/api/v1/write" - remoteWriteName = "prometheus-meta-operator" + remoteWriteName = "mimir" + remoteWriteEndpointTemplateURL = "https://mimir.%s/api/v1/push" ) type RemoteWriteConfig struct { From 8cfeac7db837b36c5ef3b68dd6f8e61a9a368076 Mon Sep 17 00:00:00 2001 From: Taylor Bot Date: Thu, 6 Jun 2024 16:56:00 +0300 Subject: [PATCH 3/3] Release v0.1.0 (#36) --- CHANGELOG.md | 5 ++++- helm/observability-operator/Chart.yaml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 403acfbe..c8634f03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.0] - 2024-06-06 + ### Add - Add support for mimir in remoteWrite secret creation. @@ -44,7 +46,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initialize project and create heartbeat for the installation. -[Unreleased]: https://github.com/giantswarm/observability-operator/compare/v0.0.4...HEAD +[Unreleased]: https://github.com/giantswarm/observability-operator/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/giantswarm/observability-operator/compare/v0.0.4...v0.1.0 [0.0.4]: https://github.com/giantswarm/observability-operator/compare/v0.0.3...v0.0.4 [0.0.3]: https://github.com/giantswarm/observability-operator/compare/v0.0.2...v0.0.3 [0.0.2]: https://github.com/giantswarm/observability-operator/compare/v0.0.1...v0.0.2 diff --git a/helm/observability-operator/Chart.yaml b/helm/observability-operator/Chart.yaml index f8c4ebbc..27a3e008 100644 --- a/helm/observability-operator/Chart.yaml +++ b/helm/observability-operator/Chart.yaml @@ -3,7 +3,7 @@ name: observability-operator description: The observability-operator manages the Giant Swarm observability platform. home: https://github.com/giantswarm/observability-operator icon: https://s.giantswarm.io/app-icons/giantswarm/1/light.svg -version: 0.0.4 +version: 0.1.0 appVersion: 0.0.2 annotations: application.giantswarm.io/team: "atlas"