Skip to content

Commit

Permalink
Merge branch 'master' into control-tekton-image
Browse files Browse the repository at this point in the history
  • Loading branch information
nilsgstrabo authored Jan 22, 2024
2 parents 69547de + 3ff031e commit af49be5
Show file tree
Hide file tree
Showing 40 changed files with 1,267 additions and 1,103 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ mocks: bootstrap
mockgen -source ./api/deployments/deployment_handler.go -destination ./api/deployments/mock/deployment_handler_mock.go -package mock
mockgen -source ./api/environments/job_handler.go -destination ./api/environments/mock/job_handler_mock.go -package mock
mockgen -source ./api/environments/environment_handler.go -destination ./api/environments/mock/environment_handler_mock.go -package mock
mockgen -source ./api/utils/tlsvalidator/interface.go -destination ./api/utils/tlsvalidator/mock/tls_secret_validator_mock.go -package mock
mockgen -source ./api/utils/tlsvalidation/interface.go -destination ./api/utils/tlsvalidation/mock/tls_secret_validator_mock.go -package mock
mockgen -source ./api/utils/jobscheduler/interface.go -destination ./api/utils/jobscheduler/mock/job_scheduler_factory_mock.go -package mock
mockgen -source ./api/events/event_handler.go -destination ./api/events/mock/event_handler_mock.go -package mock

Expand Down
21 changes: 15 additions & 6 deletions api/applications/models/pipeline_parameters.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package models

import jobModels "github.com/equinor/radix-api/api/jobs/models"
import (
jobModels "github.com/equinor/radix-api/api/jobs/models"
)

// PipelineParametersPromote identify deployment to promote and a target environment
// swagger:model PipelineParametersPromote
Expand Down Expand Up @@ -121,15 +123,22 @@ type PipelineParametersDeploy struct {
// OPTIONAL for information only
//
// example: 4faca8595c5283a9d0f17a623b9255a0d9866a2e
CommitID string `json:"commitID"`
CommitID string `json:"commitID,omitempty"`

// ComponentsToDeploy List of components to deploy
// OPTIONAL If specified, only these components are deployed
//
// required: false
ComponentsToDeploy []string `json:"componentsToDeploy"`
}

// MapPipelineParametersDeployToJobParameter maps to JobParameter
func (deployParam PipelineParametersDeploy) MapPipelineParametersDeployToJobParameter() *jobModels.JobParameters {
return &jobModels.JobParameters{
ToEnvironment: deployParam.ToEnvironment,
TriggeredBy: deployParam.TriggeredBy,
ImageTagNames: deployParam.ImageTagNames,
CommitID: deployParam.CommitID,
ToEnvironment: deployParam.ToEnvironment,
TriggeredBy: deployParam.TriggeredBy,
ImageTagNames: deployParam.ImageTagNames,
CommitID: deployParam.CommitID,
ComponentsToDeploy: deployParam.ComponentsToDeploy,
}
}
37 changes: 0 additions & 37 deletions api/deployments/component_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,43 +100,6 @@ func TestGetComponents_active_deployment(t *testing.T) {
assert.Equal(t, 1, len(job.Replicas))
}

func TestGetComponents_WithExternalAlias_ContainsTLSSecrets(t *testing.T) {
// Setup
commonTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient := setupTest(t)
err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, operatorUtils.ARadixDeployment().
WithAppName("any-app").
WithEnvironment("prod").
WithDeploymentName(anyDeployName).
WithJobComponents().
WithComponents(
operatorUtils.NewDeployComponentBuilder().
WithName("frontend").
WithPort("http", 8080).
WithPublicPort("http").
WithDNSExternalAlias("some.alias.com").
WithDNSExternalAlias("another.alias.com")))
require.NoError(t, err)

// Test
endpoint := createGetComponentsEndpoint(anyAppName, anyDeployName)

responseChannel := controllerTestUtils.ExecuteRequest("GET", endpoint)
response := <-responseChannel

assert.Equal(t, 200, response.Code)

var components []deploymentModels.Component
err = controllertest.GetResponseBody(response, &components)
require.NoError(t, err)

frontend := getComponentByName("frontend", components)
assert.Equal(t, 4, len(frontend.Secrets))
assert.Equal(t, "some.alias.com-cert", frontend.Secrets[0])
assert.Equal(t, "some.alias.com-key", frontend.Secrets[1])
assert.Equal(t, "another.alias.com-cert", frontend.Secrets[2])
assert.Equal(t, "another.alias.com-key", frontend.Secrets[3])
}

func TestGetComponents_WithVolumeMount_ContainsVolumeMountSecrets(t *testing.T) {
// Setup
commonTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient := setupTest(t)
Expand Down
3 changes: 0 additions & 3 deletions api/deployments/deployment_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,12 +359,10 @@ func TestGetDeployment_TwoDeploymentsFirstDeployment_ReturnsDeploymentWithCompon
WithImage("radixdev.azurecr.io/some-image:imagetag").
WithName("frontend").
WithPort("http", 8080).
WithPublic(true).
WithReplicas(commontest.IntPtr(1)),
builders.NewDeployComponentBuilder().
WithImage("radixdev.azurecr.io/another-image:imagetag").
WithName("backend").
WithPublic(false).
WithReplicas(commontest.IntPtr(1))))
require.NoError(t, err)

Expand All @@ -387,7 +385,6 @@ func TestGetDeployment_TwoDeploymentsFirstDeployment_ReturnsDeploymentWithCompon
builders.NewDeployComponentBuilder().
WithImage("radixdev.azurecr.io/another-second-image:imagetag").
WithName("backend").
WithPublic(false).
WithReplicas(commontest.IntPtr(1))))
require.NoError(t, err)

Expand Down
17 changes: 9 additions & 8 deletions api/deployments/models/component_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type ComponentBuilder interface {
WithAuxiliaryResource(AuxiliaryResource) ComponentBuilder
WithNotifications(*v1.Notifications) ComponentBuilder
WithHorizontalScalingSummary(*HorizontalScalingSummary) ComponentBuilder
WithExternalDNS(externalDNS []ExternalDNS) ComponentBuilder
BuildComponentSummary() (*ComponentSummary, error)
BuildComponent() (*Component, error)
}
Expand All @@ -45,6 +46,7 @@ type componentBuilder struct {
identity *Identity
notifications *Notifications
hpa *HorizontalScalingSummary
externalDNS []ExternalDNS
errors []error
}

Expand Down Expand Up @@ -100,14 +102,6 @@ func (b *componentBuilder) WithComponent(component v1.RadixCommonDeployComponent

b.ports = ports
b.secrets = component.GetSecrets()
if b.secrets == nil {
b.secrets = []string{}
}

for _, externalAlias := range component.GetDNSExternalAlias() {
b.secrets = append(b.secrets, externalAlias+suffix.ExternalDNSTLSCert)
b.secrets = append(b.secrets, externalAlias+suffix.ExternalDNSTLSKey)
}

for _, volumeMount := range component.GetVolumeMounts() {
volumeMountType := deployment.GetCsiAzureVolumeMountType(&volumeMount)
Expand Down Expand Up @@ -189,6 +183,11 @@ func (b *componentBuilder) WithHorizontalScalingSummary(hpa *HorizontalScalingSu
return b
}

func (b *componentBuilder) WithExternalDNS(externalDNS []ExternalDNS) ComponentBuilder {
b.externalDNS = externalDNS
return b
}

func (b *componentBuilder) buildError() error {
if len(b.errors) == 0 {
return nil
Expand Down Expand Up @@ -230,7 +229,9 @@ func (b *componentBuilder) BuildComponent() (*Component, error) {
AuxiliaryResource: b.auxResource,
Identity: b.identity,
Notifications: b.notifications,
ExternalDNS: b.externalDNS,
HorizontalScalingSummary: b.hpa,
CommitID: variables[defaults.RadixCommitHashEnvironmentVariable],
}, b.buildError()
}

Expand Down
25 changes: 25 additions & 0 deletions api/deployments/models/component_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,34 @@ type Component struct {
// Notifications is the spec for notification about internal events or changes
Notifications *Notifications `json:"notifications,omitempty"`

// Array of external DNS configurations
//
// required: false
ExternalDNS []ExternalDNS `json:"externalDNS,omitempty"`

// Commit ID for the component. It can be different from the Commit ID, specified in deployment label
//
// required: false
CommitID string `json:"commitID,omitempty"`

AuxiliaryResource `json:",inline"`
}

// ExternalDNS describes an external DNS entry for a component
// swagger:model ExternalDNS
type ExternalDNS struct {
// Fully Qualified Domain Name
//
// required: true
// example: site.example.com
FQDN string `json:"fqdn"`

// TLS configuration
//
// required: true
TLS TLS `json:"tls"`
}

// Identity describes external identities
type Identity struct {
// Azure identity
Expand Down
106 changes: 106 additions & 0 deletions api/deployments/models/tls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package models

import (
"crypto/x509"
"encoding/pem"
"time"
)

// swagger:enum TLSStatusEnum
type TLSStatusEnum string

const (
// TLS certificate and private key not set
TLSStatusPending TLSStatusEnum = "Pending"
// TLS certificate and private key is valid
TLSStatusConsistent TLSStatusEnum = "Consistent"
// TLS certificate and private key is invalid
TLSStatusInvalid TLSStatusEnum = "Invalid"
)

// TLS configuration and status for external DNS
// swagger:model TLS
type TLS struct {
// UseAutomation describes if TLS certificate is automatically issued using automation (ACME)
//
// required: true
UseAutomation bool `json:"useAutomation"`

// Status of TLS certificate and private key
//
// required: true
// example: Consistent
Status TLSStatusEnum `json:"status"`

// StatusMessages contains a list of messages related to Status
//
// required: false
StatusMessages []string `json:"statusMessages,omitempty"`

// Certificates holds the X509 certificate chain
// The first certificate in the list should be the host certificate and the rest should be intermediate certificates
//
// required: false
Certificates []X509Certificate `json:"certificates,omitempty"`
}

// X509Certificate holds information about a X509 certificate
// swagger:model X509Certificate
type X509Certificate struct {
// Subject contains the distinguished name for the certificate
//
// required: true
// example: CN=mysite.example.com,O=MyOrg,L=MyLocation,C=NO
Subject string `json:"subject"`
// Issuer contains the distinguished name for the certificate's issuer
//
// required: true
// example: CN=DigiCert TLS RSA SHA256 2020 CA1,O=DigiCert Inc,C=US
Issuer string `json:"issuer"`
// NotBefore defines the lower date/time validity boundary
//
// required: true
// swagger:strfmt date-time
// example: 2022-08-09T00:00:00Z
NotBefore time.Time `json:"notBefore"`
// NotAfter defines the uppdater date/time validity boundary
//
// required: true
// swagger:strfmt date-time
// example: 2023-08-25T23:59:59Z
NotAfter time.Time `json:"notAfter"`
// DNSNames defines list of Subject Alternate Names in the certificate
//
// required: false
DNSNames []string `json:"dnsNames,omitempty"`
}

// ParseX509CertificatesFromPEM builds an array of X509Certificate from PEM encoded data
func ParseX509CertificatesFromPEM(certBytes []byte) []X509Certificate {
var certs []X509Certificate
for len(certBytes) > 0 {
var block *pem.Block
block, certBytes = pem.Decode(certBytes)
if block == nil {
break
}
if block.Type != "CERTIFICATE" {
continue
}

cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
continue
}

certs = append(certs, X509Certificate{
Subject: cert.Subject.String(),
Issuer: cert.Issuer.String(),
DNSNames: cert.DNSNames,
NotBefore: cert.NotBefore,
NotAfter: cert.NotAfter,
})
}

return certs
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package models
package models_test

import (
"bytes"
Expand All @@ -11,19 +11,20 @@ import (
"testing"
"time"

"github.com/equinor/radix-api/api/deployments/models"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)

func Test_TlsCertificateTestSuite(t *testing.T) {
suite.Run(t, new(tlsCertificateTestSuite))
func Test_X509CertificateTestSuite(t *testing.T) {
suite.Run(t, new(x509CertificateTestSuite))
}

type tlsCertificateTestSuite struct {
type x509CertificateTestSuite struct {
suite.Suite
}

func (s *tlsCertificateTestSuite) Test_ParseTLSCertificatesFromPEM_ValidPEM() {
func (s *x509CertificateTestSuite) Test_ParseX509CertificatesFromPEM_ValidPEM() {
cn1, ca1, dns1 := "cn1", "ca1", []string{"dns1_1", "dns1_2"}
notBefore1, _ := time.Parse("2006-01-02", "2020-07-01")
notAfter1, _ := time.Parse("2006-01-02", "2020-08-01")
Expand All @@ -36,20 +37,20 @@ func (s *tlsCertificateTestSuite) Test_ParseTLSCertificatesFromPEM_ValidPEM() {
b := bytes.NewBuffer(cert1)
b.Write(cert2)

expected := []TLSCertificate{
expected := []models.X509Certificate{
{Subject: "CN=" + cn1, Issuer: "CN=" + ca1, NotBefore: notBefore1, NotAfter: notAfter1, DNSNames: dns1},
{Subject: "CN=" + cn2, Issuer: "CN=" + ca2, NotBefore: notBefore2, NotAfter: notAfter2, DNSNames: dns2},
}
certs := ParseTLSCertificatesFromPEM(b.Bytes())
certs := models.ParseX509CertificatesFromPEM(b.Bytes())
s.Equal(expected, certs)
}

func (s *tlsCertificateTestSuite) Test_ParseTLSCertificatesFromPEM_EmptyPEM() {
certs := ParseTLSCertificatesFromPEM(nil)
func (s *x509CertificateTestSuite) Test_ParseX509CertificatesFromPEM_EmptyPEM() {
certs := models.ParseX509CertificatesFromPEM(nil)
s.Empty(certs)
}

func (s *tlsCertificateTestSuite) Test_ParseTLSCertificatesFromPEM_NonCertificatePEM() {
func (s *x509CertificateTestSuite) Test_ParseX509CertificatesFromPEM_NonCertificatePEM() {
cn1, ca1, dns1 := "cn1", "ca1", []string{"dns1_1", "dns1_2"}
notBefore1, _ := time.Parse("2006-01-02", "2020-07-01")
notAfter1, _ := time.Parse("2006-01-02", "2020-08-01")
Expand All @@ -66,14 +67,14 @@ func (s *tlsCertificateTestSuite) Test_ParseTLSCertificatesFromPEM_NonCertificat
b := bytes.NewBuffer(cert1)
b.Write(certBuf.Bytes())

expected := []TLSCertificate{
expected := []models.X509Certificate{
{Subject: "CN=" + cn1, Issuer: "CN=" + ca1, NotBefore: notBefore1, NotAfter: notAfter1, DNSNames: dns1},
}
certs := ParseTLSCertificatesFromPEM(b.Bytes())
certs := models.ParseX509CertificatesFromPEM(b.Bytes())
s.Equal(expected, certs)
}

func (s *tlsCertificateTestSuite) Test_ParseTLSCertificatesFromPEM_InvalidPEMData() {
func (s *x509CertificateTestSuite) Test_ParseX509CertificatesFromPEM_InvalidPEMData() {
cn1, ca1, dns1 := "cn1", "ca1", []string{"dns1_1", "dns1_2"}
notBefore1, _ := time.Parse("2006-01-02", "2020-07-01")
notAfter1, _ := time.Parse("2006-01-02", "2020-08-01")
Expand All @@ -90,14 +91,14 @@ func (s *tlsCertificateTestSuite) Test_ParseTLSCertificatesFromPEM_InvalidPEMDat
b := bytes.NewBuffer(cert1)
b.Write(certBuf.Bytes())

expected := []TLSCertificate{
expected := []models.X509Certificate{
{Subject: "CN=" + cn1, Issuer: "CN=" + ca1, NotBefore: notBefore1, NotAfter: notAfter1, DNSNames: dns1},
}
certs := ParseTLSCertificatesFromPEM(b.Bytes())
certs := models.ParseX509CertificatesFromPEM(b.Bytes())
s.Equal(expected, certs)
}

func (s *tlsCertificateTestSuite) buildCert(certCN, issuerCN string, notBefore, notAfter time.Time, dnsNames []string) []byte {
func (s *x509CertificateTestSuite) buildCert(certCN, issuerCN string, notBefore, notAfter time.Time, dnsNames []string) []byte {
ca := &x509.Certificate{
SerialNumber: big.NewInt(1111),
Subject: pkix.Name{CommonName: issuerCN},
Expand Down
Loading

0 comments on commit af49be5

Please sign in to comment.