<commit_before>/*
 * Copyright 2014 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.netflix.spinnaker.oort.aws.provider.view

import com.netflix.frigga.Names
import com.netflix.spinnaker.cats.cache.Cache
import com.netflix.spinnaker.cats.cache.CacheData
import com.netflix.spinnaker.cats.cache.CacheFilter
import com.netflix.spinnaker.cats.cache.RelationshipCacheFilter
import com.netflix.spinnaker.clouddriver.model.LoadBalancerProvider
import com.netflix.spinnaker.oort.aws.data.Keys
import com.netflix.spinnaker.oort.aws.model.AmazonInstance
import com.netflix.spinnaker.oort.aws.model.AmazonLoadBalancer
import com.netflix.spinnaker.oort.aws.model.AmazonServerGroup
import com.netflix.spinnaker.oort.aws.provider.AwsProvider
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.APPLICATIONS
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.CLUSTERS
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.HEALTH
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.INSTANCES
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.LOAD_BALANCERS
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.SERVER_GROUPS

@Component
class CatsLoadBalancerProvider implements LoadBalancerProvider<AmazonLoadBalancer> {

  private final Cache cacheView
  private final AwsProvider awsProvider

  @Autowired
  public CatsLoadBalancerProvider(Cache cacheView, AwsProvider awsProvider) {
    this.cacheView = cacheView
    this.awsProvider = awsProvider
  }

  @Override
  Map<String, Set<AmazonLoadBalancer>> getLoadBalancers() {
    Map<String, Set<AmazonLoadBalancer>> partitionedLb = [:].withDefault { new HashSet<AmazonLoadBalancer>() }
    Collection<AmazonLoadBalancer> allLb = cacheView.getAll(LOAD_BALANCERS.ns).findResults(this.&translate)
    for (AmazonLoadBalancer lb : allLb) {
      partitionedLb[lb.account].add(lb)
    }
  }

  AmazonLoadBalancer translate(CacheData cacheData) {
    Map<String, String> keyParts = Keys.parse(cacheData.id)
    def lb = new AmazonLoadBalancer(name: keyParts.loadBalancer, account: keyParts.account, region: keyParts.region)
    lb.account = keyParts.account
    lb.elb = cacheData.attributes
    lb.serverGroups = cacheData.relationships[SERVER_GROUPS.ns]?.collect {
      Map<String, String> sgParts = Keys.parse(it)
      sgParts.cluster
    } ?: []
  }

  Collection<CacheData> resolveRelationshipData(CacheData source, String relationship) {
    source.relationships[relationship] ? cacheView.getAll(relationship, source.relationships[relationship]) : []
  }

  private Collection<CacheData> resolveRelationshipDataForCollection(Collection<CacheData> sources, String relationship, CacheFilter cacheFilter = null) {
    Set<String> relationships = sources.findResults { it.relationships[relationship]?: [] }.flatten()
    relationships ? cacheView.getAll(relationship, relationships, cacheFilter) : []
  }

  @Override
  Set<AmazonLoadBalancer> getLoadBalancers(String account) {
    def searchKey = Keys.getLoadBalancerKey('*', account, '*', null)
    def filteredIds = cacheView.filterIdentifiers(LOAD_BALANCERS.ns, searchKey)
    cacheView.getAll(LOAD_BALANCERS.ns, filteredIds).findResults(this.&translate) as Set<AmazonLoadBalancer>
  }

  @Override
  Set<AmazonLoadBalancer> getLoadBalancers(String account, String cluster) {
    Names names = Names.parseName(cluster)
    CacheData clusterData = cacheView.get(CLUSTERS.ns, Keys.getClusterKey(cluster, names.app, account))

    resolveRelationshipData(clusterData, LOAD_BALANCERS.ns).findResults(this.&translate)
  }

  @Override
  Set<AmazonLoadBalancer> getLoadBalancers(String account, String cluster, String type) {
    getLoadBalancers(account, cluster)
  }

  @Override
  Set<AmazonLoadBalancer> getLoadBalancer(String account, String cluster, String type, String loadBalancerName) {
    getLoadBalancers(account, cluster).findAll { it.name == loadBalancerName }
  }

  @Override
  AmazonLoadBalancer getLoadBalancer(String account, String cluster, String type, String loadBalancerName, String region) {
    def searchKey = Keys.getLoadBalancerKey(loadBalancerName, account, region, null) + '*'
    def lbs = cacheView.filterIdentifiers(LOAD_BALANCERS.ns, searchKey)
    def keys = lbs.findAll {
      Keys.parse(it).loadBalancer == loadBalancerName
    }

    def candidates = cacheView.getAll(LOAD_BALANCERS.ns, keys).findResults(this.&translate)
    if (candidates.isEmpty()) {
      null
    } else {
      candidates.first()
    }
  }

  @Override
  Set<AmazonLoadBalancer> getApplicationLoadBalancers(String applicationName) {

    Map<String, AmazonServerGroup> serverGroups
    Set<String> keys = []

    CacheData application = cacheView.get(APPLICATIONS.ns, Keys.getApplicationKey(applicationName))

    def applicationServerGroups = application ? resolveRelationshipData(application, SERVER_GROUPS.ns) : []
    applicationServerGroups.each { CacheData serverGroup ->
      keys.addAll(serverGroup.relationships[LOAD_BALANCERS.ns] ?: [])
    }

    def nameMatches = cacheView.filterIdentifiers(LOAD_BALANCERS.ns, '*:' + applicationName + '-*')
    // include non-VPC exact matches
    nameMatches.addAll(cacheView.filterIdentifiers(LOAD_BALANCERS.ns, '*:' + applicationName));
    // include VPC exact matches
    nameMatches.addAll(cacheView.filterIdentifiers(LOAD_BALANCERS.ns, '*:' + applicationName + ':*'));

    keys.addAll(nameMatches)

    def allLoadBalancers = cacheView.getAll(LOAD_BALANCERS.ns, keys)<commit_msg>Restrict AWS load balancer cache lookup via 'aws:' so it does not pick up other providers' load balancers.<commit_after>/*
 * Copyright 2014 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.netflix.spinnaker.oort.aws.provider.view

import com.netflix.frigga.Names
import com.netflix.spinnaker.cats.cache.Cache
import com.netflix.spinnaker.cats.cache.CacheData
import com.netflix.spinnaker.cats.cache.CacheFilter
import com.netflix.spinnaker.cats.cache.RelationshipCacheFilter
import com.netflix.spinnaker.clouddriver.model.LoadBalancerProvider
import com.netflix.spinnaker.oort.aws.data.Keys
import com.netflix.spinnaker.oort.aws.model.AmazonInstance
import com.netflix.spinnaker.oort.aws.model.AmazonLoadBalancer
import com.netflix.spinnaker.oort.aws.model.AmazonServerGroup
import com.netflix.spinnaker.oort.aws.provider.AwsProvider
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.APPLICATIONS
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.CLUSTERS
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.HEALTH
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.INSTANCES
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.LOAD_BALANCERS
import static com.netflix.spinnaker.oort.aws.data.Keys.Namespace.SERVER_GROUPS

@Component
class CatsLoadBalancerProvider implements LoadBalancerProvider<AmazonLoadBalancer> {

  private final Cache cacheView
  private final AwsProvider awsProvider

  @Autowired
  public CatsLoadBalancerProvider(Cache cacheView, AwsProvider awsProvider) {
    this.cacheView = cacheView
    this.awsProvider = awsProvider
  }

  @Override
  Map<String, Set<AmazonLoadBalancer>> getLoadBalancers() {
    Map<String, Set<AmazonLoadBalancer>> partitionedLb = [:].withDefault { new HashSet<AmazonLoadBalancer>() }
    Collection<AmazonLoadBalancer> allLb = cacheView.getAll(LOAD_BALANCERS.ns).findResults(this.&translate)
    for (AmazonLoadBalancer lb : allLb) {
      partitionedLb[lb.account].add(lb)
    }
  }

  AmazonLoadBalancer translate(CacheData cacheData) {
    Map<String, String> keyParts = Keys.parse(cacheData.id)
    def lb = new AmazonLoadBalancer(name: keyParts.loadBalancer, account: keyParts.account, region: keyParts.region)
    lb.account = keyParts.account
    lb.elb = cacheData.attributes
    lb.serverGroups = cacheData.relationships[SERVER_GROUPS.ns]?.collect {
      Map<String, String> sgParts = Keys.parse(it)
      sgParts.cluster
    } ?: []
  }

  Collection<CacheData> resolveRelationshipData(CacheData source, String relationship) {
    source.relationships[relationship] ? cacheView.getAll(relationship, source.relationships[relationship]) : []
  }

  private Collection<CacheData> resolveRelationshipDataForCollection(Collection<CacheData> sources, String relationship, CacheFilter cacheFilter = null) {
    Set<String> relationships = sources.findResults { it.relationships[relationship]?: [] }.flatten()
    relationships ? cacheView.getAll(relationship, relationships, cacheFilter) : []
  }

  @Override
  Set<AmazonLoadBalancer> getLoadBalancers(String account) {
    def searchKey = Keys.getLoadBalancerKey('*', account, '*', null)
    def filteredIds = cacheView.filterIdentifiers(LOAD_BALANCERS.ns, searchKey)
    cacheView.getAll(LOAD_BALANCERS.ns, filteredIds).findResults(this.&translate) as Set<AmazonLoadBalancer>
  }

  @Override
  Set<AmazonLoadBalancer> getLoadBalancers(String account, String cluster) {
    Names names = Names.parseName(cluster)
    CacheData clusterData = cacheView.get(CLUSTERS.ns, Keys.getClusterKey(cluster, names.app, account))

    resolveRelationshipData(clusterData, LOAD_BALANCERS.ns).findResults(this.&translate)
  }

  @Override
  Set<AmazonLoadBalancer> getLoadBalancers(String account, String cluster, String type) {
    getLoadBalancers(account, cluster)
  }

  @Override
  Set<AmazonLoadBalancer> getLoadBalancer(String account, String cluster, String type, String loadBalancerName) {
    getLoadBalancers(account, cluster).findAll { it.name == loadBalancerName }
  }

  @Override
  AmazonLoadBalancer getLoadBalancer(String account, String cluster, String type, String loadBalancerName, String region) {
    def searchKey = Keys.getLoadBalancerKey(loadBalancerName, account, region, null) + '*'
    def lbs = cacheView.filterIdentifiers(LOAD_BALANCERS.ns, searchKey)
    def keys = lbs.findAll {
      Keys.parse(it).loadBalancer == loadBalancerName
    }

    def candidates = cacheView.getAll(LOAD_BALANCERS.ns, keys).findResults(this.&translate)
    if (candidates.isEmpty()) {
      null
    } else {
      candidates.first()
    }
  }

  @Override
  Set<AmazonLoadBalancer> getApplicationLoadBalancers(String applicationName) {

    Map<String, AmazonServerGroup> serverGroups
    Set<String> keys = []

    CacheData application = cacheView.get(APPLICATIONS.ns, Keys.getApplicationKey(applicationName))

    def applicationServerGroups = application ? resolveRelationshipData(application, SERVER_GROUPS.ns) : []
    applicationServerGroups.each { CacheData serverGroup ->
      keys.addAll(serverGroup.relationships[LOAD_BALANCERS.ns] ?: [])
    }

    def nameMatches = cacheView.filterIdentifiers(LOAD_BALANCERS.ns, 'aws:*:' + applicationName + '-*')
    // include non-VPC exact matches
    nameMatches.addAll(cacheView.filterIdentifiers(LOAD_BALANCERS.ns, 'aws:*:' + applicationName));
    // include VPC exact matches
    nameMatches.addAll(cacheView.filterIdentifiers(LOAD_BALANCERS.ns, 'aws:*:' + applicationName + ':*'));

    keys.addAll(nameMatches)

    def allLoadBalancers = cacheView.getAll(LOAD_BALANCERS.ns, keys)
{'fraction_non_alphanumeric': 0.09864027677206533, 'fraction_numerical': 0.0012873119317724675, 'mean_word_length': 5.078239608801956, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3878751', 'n_tokens_mistral': 3855, 'n_tokens_neox': 3680, 'n_words': 739}