Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MESH-5405-Create prefixed SEs #336

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 87 additions & 63 deletions admiral/pkg/clusters/configwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import (
networkingV1Alpha3 "istio.io/api/networking/v1alpha3"
)

const typeLabel = "type"
const (
typeLabel = "type"
testServiceKey = "canary"
defaultServiceKey = "default"
canaryPrefix = "canary"
previewPrefix = "preview"
)

// IstioSEBuilder is an interface to construct Service Entry objects
// from IdentityConfig objects. It can construct multiple Service Entries
Expand All @@ -35,7 +41,7 @@ type ServiceEntryBuilder struct {
func (b *ServiceEntryBuilder) BuildServiceEntriesFromIdentityConfig(ctxLogger *logrus.Entry, identityConfig registry.IdentityConfig) ([]*networkingV1Alpha3.ServiceEntry, error) {
var (
identity = identityConfig.IdentityName
seMap = map[string]*networkingV1Alpha3.ServiceEntry{}
seMap = map[string]map[string]*networkingV1Alpha3.ServiceEntry{}
serviceEntries = []*networkingV1Alpha3.ServiceEntry{}
start = time.Now()
err error
Expand All @@ -58,37 +64,61 @@ func (b *ServiceEntryBuilder) BuildServiceEntriesFromIdentityConfig(ctxLogger *l
serverCluster := identityConfigCluster.Name
for _, identityConfigEnvironment := range identityConfigCluster.Environment {
env := identityConfigEnvironment.Name
var tmpSe *networkingV1Alpha3.ServiceEntry
start = time.Now()
endpoints, err := getServiceEntryEndpoints(ctxLogger, b.ClientCluster, serverCluster, ingressEndpoints, identityConfigEnvironment)
util.LogElapsedTimeSince("getServiceEntryEndpoint", identity, env, b.ClientCluster, start)
if err != nil {
return serviceEntries, err
if len(identityConfigEnvironment.Services) == 0 {
return serviceEntries, fmt.Errorf("there were no services for the asset in namespace %s on cluster %s", identityConfigEnvironment.Namespace, serverCluster)
}
if se, ok := seMap[env]; !ok {
tmpSe = &networkingV1Alpha3.ServiceEntry{
Hosts: []string{common.GetCnameVal([]string{env, strings.ToLower(identity), common.GetHostnameSuffix()})},
Ports: identityConfigEnvironment.Ports,
Location: networkingV1Alpha3.ServiceEntry_MESH_INTERNAL,
Resolution: networkingV1Alpha3.ServiceEntry_DNS,
SubjectAltNames: []string{common.SpiffePrefix + common.GetSANPrefix() + common.Slash + identity},
Endpoints: endpoints,
ExportTo: dependentNamespaces,

start = time.Now()
meshHosts := getMeshHosts(identity, identityConfigEnvironment)
for _, host := range meshHosts {
var tmpSe *networkingV1Alpha3.ServiceEntry
endpoints, err := getServiceEntryEndpoints(ctxLogger, b.ClientCluster, serverCluster, host, ingressEndpoints, identityConfigEnvironment)
util.LogElapsedTimeSince("getServiceEntryEndpoint", identity, env, b.ClientCluster, start)
if err != nil {
return serviceEntries, err
}
if se, ok := seMap[env][host]; !ok {
tmpSe = &networkingV1Alpha3.ServiceEntry{
Hosts: []string{host},
Ports: identityConfigEnvironment.Ports,
Location: networkingV1Alpha3.ServiceEntry_MESH_INTERNAL,
Resolution: networkingV1Alpha3.ServiceEntry_DNS,
SubjectAltNames: []string{common.SpiffePrefix + common.GetSANPrefix() + common.Slash + identity},
Endpoints: endpoints,
ExportTo: dependentNamespaces,
}
} else {
tmpSe = se
tmpSe.Endpoints = append(tmpSe.Endpoints, endpoints...)
}
} else {
tmpSe = se
tmpSe.Endpoints = append(tmpSe.Endpoints, endpoints...)
sort.Sort(WorkloadEntrySorted(tmpSe.Endpoints))
seMap[env] = map[string]*networkingV1Alpha3.ServiceEntry{host: tmpSe}
}
sort.Sort(WorkloadEntrySorted(tmpSe.Endpoints))
seMap[env] = tmpSe
}
}
for _, se := range seMap {
serviceEntries = append(serviceEntries, se)
for _, seForEnv := range seMap {
for _, se := range seForEnv {
serviceEntries = append(serviceEntries, se)
}
}
return serviceEntries, err
}

func getMeshHosts(identity string, identityConfigEnvironment *registry.IdentityConfigEnvironment) []string {
meshHosts := []string{}
meshHosts = append(meshHosts, common.GetCnameVal([]string{identityConfigEnvironment.Name, strings.ToLower(identity), common.GetHostnameSuffix()}))
if identityConfigEnvironment.Type[common.Rollout] != nil {
strategy := identityConfigEnvironment.Type[common.Rollout].Strategy
if strategy == bluegreenStrategy {
meshHosts = append(meshHosts, common.GetCnameVal([]string{previewPrefix, strings.ToLower(identity), common.GetHostnameSuffix()}))
}
if strategy == canaryStrategy {
meshHosts = append(meshHosts, common.GetCnameVal([]string{canaryPrefix, strings.ToLower(identity), common.GetHostnameSuffix()}))
}
}
return meshHosts
}

// getIngressEndpoints constructs the endpoint of the ingress gateway/remote endpoint for an identity
// by reading the information directly from the IdentityConfigCluster.
func getIngressEndpoints(clusters map[string]*registry.IdentityConfigCluster) (map[string]*networkingV1Alpha3.WorkloadEntry, error) {
Expand Down Expand Up @@ -116,56 +146,50 @@ func getServiceEntryEndpoints(
ctxLogger *logrus.Entry,
clientCluster string,
serverCluster string,
host string,
ingressEndpoints map[string]*networkingV1Alpha3.WorkloadEntry,
identityConfigEnvironment *registry.IdentityConfigEnvironment) ([]*networkingV1Alpha3.WorkloadEntry, error) {
if len(identityConfigEnvironment.Services) == 0 {
return nil, fmt.Errorf("there were no services for the asset in namespace %s on cluster %s", identityConfigEnvironment.Namespace, serverCluster)
}
var err error
services := identityConfigEnvironment.Services
endpoint := ingressEndpoints[serverCluster]
endpoints := []*networkingV1Alpha3.WorkloadEntry{}
tmpEp := endpoint.DeepCopy()
tmpEp.Labels[typeLabel] = identityConfigEnvironment.Type
services := []*registry.RegistryServiceConfig{}
for _, service := range identityConfigEnvironment.Services {
services = append(services, service)
}
sort.Sort(registry.RegistryServiceConfigSorted(services))
// Deployment won't have weights, so just sort and take the first service to use as the endpoint
if identityConfigEnvironment.Type == common.Deployment {
if clientCluster == serverCluster {
tmpEp.Address = services[0].Name + common.Sep + identityConfigEnvironment.Namespace + common.GetLocalDomainSuffix()
tmpEp.Ports = services[0].Ports
}
endpoints = append(endpoints, tmpEp)

if services == nil {
return endpoints, fmt.Errorf("services are nil for identityConfigEnvironment %s", identityConfigEnvironment.Name)
}
// Rollout without weights is treated the same as deployment so sort and take first service
// If any of the services have weights then add them to the list of endpoints
if identityConfigEnvironment.Type == common.Rollout {
for _, service := range services {
if service.Weight > 0 {
weightedEp := tmpEp.DeepCopy()
weightedEp.Weight = uint32(service.Weight)
if clientCluster == serverCluster {
weightedEp.Address = service.Name + common.Sep + identityConfigEnvironment.Namespace + common.GetLocalDomainSuffix()
weightedEp.Ports = service.Ports

// Logic to determine which services should be against default (like whether have both rollout and deployment, and which service for which type) will move to state syncer
// Also state syncer will be responsible for setting the weight of the services, and removing services without weights if one has a weight
ep := endpoint.DeepCopy()
if clientCluster == serverCluster {
if strings.HasPrefix(host, canaryPrefix) || strings.HasPrefix(host, previewPrefix) {
ep.Address = services[testServiceKey][0].Name + common.Sep + identityConfigEnvironment.Namespace + common.GetLocalDomainSuffix()
Punakshi marked this conversation as resolved.
Show resolved Hide resolved
ep.Ports = services[testServiceKey][0].Ports
endpoints = append(endpoints, ep)
} else {
for _, service := range services[defaultServiceKey] {
tempEp := ep.DeepCopy()
tempEp.Address = service.Name + common.Sep + identityConfigEnvironment.Namespace + common.GetLocalDomainSuffix()
tempEp.Ports = service.Ports
if service.Weight > 0 {
tempEp.Weight = uint32(service.Weight)
}
endpoints = append(endpoints, weightedEp)
endpoints = append(endpoints, tempEp)
}
}
// If we go through all the services associated with the rollout and none have applicable weights then endpoints is empty
// Treat the rollout like a deployment and sort and take the first service
if len(endpoints) == 0 {
if clientCluster == serverCluster {
tmpEp.Address = services[0].Name + common.Sep + identityConfigEnvironment.Namespace + common.GetLocalDomainSuffix()
tmpEp.Ports = services[0].Ports
for _, service := range services[testServiceKey] {
if service.Weight > 0 {
tempEp := ep.DeepCopy()
tempEp.Address = service.Name + common.Sep + identityConfigEnvironment.Namespace + common.GetLocalDomainSuffix()
tempEp.Ports = service.Ports
tempEp.Weight = uint32(service.Weight)
endpoints = append(endpoints, tempEp)
}
}
endpoints = append(endpoints, tmpEp)
}
} else {
endpoints = append(endpoints, ep)
}
// TODO: type is rollout, strategy is bluegreen, need a way to know which service is preview/desired, trigger another SE
// TODO: type is rollout, strategy is canary, need a way to know which service is stable/root/desired, trigger another SE
// TODO: two types in the environment, deployment to rollout migration
sort.Sort(WorkloadEntrySorted(endpoints))
return endpoints, err
}

Expand Down
Loading