Skip to content

Commit

Permalink
feat: initial implementation of provided capabilities
Browse files Browse the repository at this point in the history
This fulfills the second part of the contract allowing components to
provided capabilities such as REST endpoints which can then be used by
other components.

Fixes #216
  • Loading branch information
metacosm committed Feb 20, 2020
1 parent 1682b6f commit a510dfa
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
56 changes: 56 additions & 0 deletions pkg/controller/component/provided_capability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package component

import (
v1beta12 "halkyon.io/api/capability/v1beta1"
"halkyon.io/api/component/v1beta1"
beta1 "halkyon.io/api/v1beta1"
framework "halkyon.io/operator-framework"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)

type providedCapability struct {
base
capabilityConfig v1beta1.CapabilityConfig
}

var _ framework.DependentResource = &providedCapability{}

func newProvidedCapability(owner *v1beta1.Component, capConfig v1beta1.CapabilityConfig) providedCapability {
config := framework.NewConfig(capabilityGVK)
config.TypeName = "Provided Capability"
c := providedCapability{base: newConfiguredBaseDependent(owner, config), capabilityConfig: capConfig}
c.NameFn = c.Name
return c
}

func (res providedCapability) Build(empty bool) (runtime.Object, error) {
capability := &v1beta12.Capability{}
if !empty {
c := res.ownerAsComponent()
ls := getAppLabels(c)
capability.ObjectMeta = v1.ObjectMeta{
Name: res.Name(),
Namespace: c.Namespace,
Labels: ls,
}
capability.Spec = res.capabilityConfig.Spec
capability.Spec.Parameters = append(capability.Spec.Parameters, beta1.NameValuePair{
Name: "component",
Value: c.Name,
})
}
return capability, nil
}

func (res providedCapability) Name() string {
return res.capabilityConfig.Name
}

func (res providedCapability) GetCondition(_ runtime.Object, _ error) *beta1.DependentCondition {
panic("should never be called")
}

func (res providedCapability) Fetch() (runtime.Object, error) {
return framework.DefaultFetcher(res)
}
57 changes: 57 additions & 0 deletions pkg/controller/component/required_capability.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@ func (res requiredCapability) Build(empty bool) (runtime.Object, error) {
return nil, nil
}

func (res requiredCapability) Update(toUpdate runtime.Object) (bool, runtime.Object, error) {
c := toUpdate.(*v1beta12.Capability)
return res.updateIfNeeded(c)
}

func (res requiredCapability) updateIfNeeded(c *v1beta12.Capability) (bool, runtime.Object, error) {
updated := false

// examine all given parameters that starts by `halkyon` as these denote parameters to pass to the underlying plugin
// as opposed to parameters used to match a capability
wanted := res.capabilityConfig.Spec.Parameters
for _, parameter := range wanted {
name := parameter.Name
if strings.HasPrefix(name, "halkyon.") {
value := parameter.Value
// try to see if that parameter was already set for that capability
found := false
for i, pair := range c.Spec.Parameters {
if pair.Name == name {
if pair.Value != value {
updated = true
c.Spec.Parameters[i] = beta1.NameValuePair{Name: name, Value: value}
}
found = true
break
}
}
// if we didn't find the parameter, add it
if !found {
updated = true
c.Spec.Parameters = append(c.Spec.Parameters, beta1.NameValuePair{Name: name, Value: value})
}
}
}
return updated, c, nil
}

func (res requiredCapability) Name() string {
return res.capabilityConfig.Name
}
Expand Down Expand Up @@ -77,6 +114,16 @@ func (res requiredCapability) Fetch() (runtime.Object, error) {
// if the referenced capability matches, return it
foundSpec := result.Spec
if matches(spec, foundSpec) {
updated, result, err := res.updateIfNeeded(result)
if err != nil {
return nil, err
}
if updated {
err := framework.Helper.Client.Update(context.Background(), result)
if err != nil {
return nil, err
}
}
return result, nil
}
return nil, fmt.Errorf("specified '%s' bound to capability doesn't match %v requirements, was: %v", config.BoundTo, selector, selectorFor(foundSpec))
Expand All @@ -101,6 +148,16 @@ func (res requiredCapability) Fetch() (runtime.Object, error) {
break
}
}
updated, result, err := res.updateIfNeeded(result)
if err != nil {
return nil, err
}
if updated {
err := framework.Helper.Client.Update(context.Background(), result)
if err != nil {
return nil, err
}
}
return result, nil
}
}
Expand Down

0 comments on commit a510dfa

Please sign in to comment.