github.com/cloudfoundry/libcfbuildpack@v1.91.23/services/services.go (about)

     1  /*
     2   * Copyright 2018-2020 the original author or authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *      https://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package services
    18  
    19  import (
    20  	"strings"
    21  
    22  	"github.com/buildpack/libbuildpack/services"
    23  )
    24  
    25  // Services is a collection of services bound to the application.
    26  type Services struct {
    27  	services.Services
    28  }
    29  
    30  // FindServiceCredentials returns the credentials payload for given service.  The selected service is one who's
    31  // BindingName, InstanceName, Label, or Tags contain the filter and has the required credentials.  Returns the
    32  // credentials and true if exactly one service is matched, otherwise false.
    33  //
    34  // NOTE: This function should ONLY be used to extract values that are CONSTANT throughout the lifecycle of a staged
    35  // application.  Typically this means you should only use this function to get agent download information from Service
    36  // Brokers and SHOULD NOT EVER retrieve and use connection credentials.
    37  func (s Services) FindServiceCredentials(filter string, credentials ...string) (Credentials, bool) {
    38  	match := make([]Service, 0)
    39  
    40  	for _, c := range s.Services {
    41  		if s.matchesService(c, filter) && s.matchesCredentials(c, credentials) {
    42  			match = append(match, c)
    43  		}
    44  	}
    45  
    46  	if len(match) != 1 {
    47  		return nil, false
    48  	}
    49  
    50  	return match[0].Credentials, true
    51  }
    52  
    53  // HasService determines whether a single service, who's BindingName, InstanceName, Label, or Tags contain the filter
    54  // and has the required credentials, exists.  Returns true if exactly one service is matched, false otherwise.
    55  func (s Services) HasService(filter string, credentials ...string) bool {
    56  	var match []Service
    57  
    58  	for _, c := range s.Services {
    59  		if s.matchesService(c, filter) && s.matchesCredentials(c, credentials) {
    60  			match = append(match, c)
    61  		}
    62  	}
    63  
    64  	return len(match) == 1
    65  }
    66  
    67  type biPredicate func(x string, y string) bool
    68  
    69  func (Services) any(test biPredicate, s string, candidates []string) bool {
    70  	for _, c := range candidates {
    71  		if test(c, s) {
    72  			return true
    73  		}
    74  	}
    75  
    76  	return false
    77  }
    78  
    79  func (Services) equality(x string, y string) bool {
    80  	return x == y
    81  }
    82  
    83  func (Services) matchesBindingName(service Service, filter string) bool {
    84  	return strings.Contains(service.BindingName, filter)
    85  }
    86  
    87  func (s Services) matchesCredentials(service Service, credentials []string) bool {
    88  	cr := service.Credentials
    89  
    90  	candidates := make([]string, 0, len(cr))
    91  	for k := range cr {
    92  		candidates = append(candidates, k)
    93  	}
    94  
    95  	for _, c := range credentials {
    96  		if !s.any(s.equality, c, candidates) {
    97  			return false
    98  		}
    99  	}
   100  
   101  	return true
   102  }
   103  
   104  func (Services) matchesInstanceName(service Service, filter string) bool {
   105  	return strings.Contains(service.InstanceName, filter)
   106  }
   107  
   108  func (Services) matchesLabel(service Service, filter string) bool {
   109  	return strings.Contains(service.Label, filter)
   110  }
   111  
   112  func (s Services) matchesService(service Service, filter string) bool {
   113  	return s.matchesBindingName(service, filter) ||
   114  		s.matchesInstanceName(service, filter) ||
   115  		s.matchesLabel(service, filter) ||
   116  		s.matchesTag(service, filter)
   117  }
   118  
   119  func (s Services) matchesTag(service Service, filter string) bool {
   120  	return s.any(strings.Contains, filter, service.Tags)
   121  }