Skip to content

Commit

Permalink
pkg/ansible; Add support to watch cluster-scoped resources (#924) (#1031
Browse files Browse the repository at this point in the history
)

* pkg/ansible; Add support to watch cluster-scoped resources=
* Update proxy command in images/scorecard-proxy
  • Loading branch information
dymurray authored and Shawn Hurley committed Feb 4, 2019
1 parent ee9f7ad commit 1d3aa60
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 127 deletions.
1 change: 1 addition & 0 deletions doc/ansible/dev/advanced_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Some features can be overridden per resource via an annotation on that CR. The o
| Reconcile Period | `reconcilePeriod` | time between reconcile runs for a particular CR | ansbile.operator-sdk/reconcile-period | 1m |
| Manage Status | `manageStatus` | Allows the ansible operator to manage the conditions section of each resource's status section. | | true |
| Watching Dependent Resources | `watchDependentResources` | Allows the ansible operator to dynamically watch resources that are created by ansible | | true |
| Watching Cluster-Scoped Resources | `watchClusterScopedResources` | Allows the ansible operator to watch cluster-scoped resources that are created by ansible | | false |
| Max Runner Artifacts | `maxRunnerArtifacts` | Manages the number of [artifact directories](https://ansible-runner.readthedocs.io/en/latest/intro.html#runner-artifacts-directory-hierarchy) that ansible runner will keep in the operator container for each individual resource. | ansible.operator-sdk/max-runner-artifacts | 20 |


Expand Down
3 changes: 2 additions & 1 deletion images/scorecard-proxy/cmd/proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"os"

proxy "github.com/operator-framework/operator-sdk/pkg/ansible/proxy"
"github.com/operator-framework/operator-sdk/pkg/ansible/proxy/controllermap"
"github.com/operator-framework/operator-sdk/pkg/k8sutil"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -47,7 +48,7 @@ func main() {
}

done := make(chan error)
cMap := proxy.NewControllerMap()
cMap := controllermap.NewControllerMap()

// start the proxy
err = proxy.Run(done, proxy.Options{
Expand Down
15 changes: 8 additions & 7 deletions pkg/ansible/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ var log = logf.Log.WithName("ansible-controller")

// Options - options for your controller
type Options struct {
EventHandlers []events.EventHandler
LoggingLevel events.LogLevel
Runner runner.Runner
GVK schema.GroupVersionKind
ReconcilePeriod time.Duration
ManageStatus bool
WatchDependentResources bool
EventHandlers []events.EventHandler
LoggingLevel events.LogLevel
Runner runner.Runner
GVK schema.GroupVersionKind
ReconcilePeriod time.Duration
ManageStatus bool
WatchDependentResources bool
WatchClusterScopedResources bool
}

// Add - Creates a new ansible operator controller and adds it to the manager
Expand Down
11 changes: 8 additions & 3 deletions pkg/ansible/operator/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

"github.com/operator-framework/operator-sdk/pkg/ansible/controller"
"github.com/operator-framework/operator-sdk/pkg/ansible/flags"
"github.com/operator-framework/operator-sdk/pkg/ansible/proxy"
"github.com/operator-framework/operator-sdk/pkg/ansible/proxy/controllermap"
"github.com/operator-framework/operator-sdk/pkg/ansible/runner"

"sigs.k8s.io/controller-runtime/pkg/manager"
Expand All @@ -32,7 +32,7 @@ import (
// Run - A blocking function which starts a controller-runtime manager
// It starts an Operator by reading in the values in `./watches.yaml`, adds a controller
// to the manager, and finally running the manager.
func Run(done chan error, mgr manager.Manager, f *flags.AnsibleOperatorFlags, cMap *proxy.ControllerMap) {
func Run(done chan error, mgr manager.Manager, f *flags.AnsibleOperatorFlags, cMap *controllermap.ControllerMap) {
watches, err := runner.NewFromWatches(f.WatchesFile)
if err != nil {
logf.Log.WithName("manager").Error(err, "Failed to get watches")
Expand All @@ -57,7 +57,12 @@ func Run(done chan error, mgr manager.Manager, f *flags.AnsibleOperatorFlags, cM
done <- errors.New("failed to add controller")
return
}
cMap.Store(o.GVK, *ctr, runner.GetWatchDependentResources())
cMap.Store(o.GVK, &controllermap.ControllerMapContents{Controller: *ctr,
WatchDependentResources: runner.GetWatchDependentResources(),
WatchClusterScopedResources: runner.GetWatchClusterScopedResources(),
WatchMap: controllermap.NewWatchMap(),
UIDMap: controllermap.NewUIDMap(),
})
}
done <- mgr.Start(c)
}
Expand Down
140 changes: 140 additions & 0 deletions pkg/ansible/proxy/controllermap/controllermap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2018 The Operator-SDK Authors
//
// 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 controllermap

import (
"sync"

"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/controller"
)

// ControllerMap - map of GVK to ControllerMapContents
type ControllerMap struct {
mutex sync.RWMutex
internal map[schema.GroupVersionKind]*ControllerMapContents
}

// UIDMap - map of UID to namespaced name of owner
type UIDMap struct {
mutex sync.RWMutex
internal map[types.UID]types.NamespacedName
}

// WatchMap - map of GVK to interface. Determines if resource is being watched already
type WatchMap struct {
mutex sync.RWMutex
internal map[schema.GroupVersionKind]interface{}
}

// ControllerMapContents- Contains internal data associated with each controller
type ControllerMapContents struct {
Controller controller.Controller
WatchDependentResources bool
WatchClusterScopedResources bool
WatchMap *WatchMap
UIDMap *UIDMap
}

// NewControllerMap returns a new object that contains a mapping between GVK
// and ControllerMapContents object
func NewControllerMap() *ControllerMap {
return &ControllerMap{
internal: make(map[schema.GroupVersionKind]*ControllerMapContents),
}
}

// NewWatchMap - returns a new object that maps GVK to interface to determine
// if resource is being watched
func NewWatchMap() *WatchMap {
return &WatchMap{
internal: make(map[schema.GroupVersionKind]interface{}),
}
}

// NewUIDMap - returns a new object that maps UID to namespaced name of owner
func NewUIDMap() *UIDMap {
return &UIDMap{
internal: make(map[types.UID]types.NamespacedName),
}
}

// Get - Returns a ControllerMapContents given a GVK as the key. `ok`
// determines if the key exists
func (cm *ControllerMap) Get(key schema.GroupVersionKind) (value *ControllerMapContents, ok bool) {
cm.mutex.RLock()
defer cm.mutex.RUnlock()
value, ok = cm.internal[key]
return value, ok
}

// Delete - Deletes associated GVK to controller mapping from the ControllerMap
func (cm *ControllerMap) Delete(key schema.GroupVersionKind) {
cm.mutex.Lock()
defer cm.mutex.Unlock()
delete(cm.internal, key)
}

// Store - Adds a new GVK to controller mapping
func (cm *ControllerMap) Store(key schema.GroupVersionKind, value *ControllerMapContents) {
cm.mutex.Lock()
defer cm.mutex.Unlock()
cm.internal[key] = value
}

// Get - Checks if GVK is already watched
func (wm *WatchMap) Get(key schema.GroupVersionKind) (value interface{}, ok bool) {
wm.mutex.RLock()
defer wm.mutex.RUnlock()
value, ok = wm.internal[key]
return value, ok
}

// Delete - Deletes associated watches for a specific GVK
func (wm *WatchMap) Delete(key schema.GroupVersionKind) {
wm.mutex.Lock()
defer wm.mutex.Unlock()
delete(wm.internal, key)
}

// Store - Adds a new GVK to be watched
func (wm *WatchMap) Store(key schema.GroupVersionKind) {
wm.mutex.Lock()
defer wm.mutex.Unlock()
wm.internal[key] = nil
}

// Get - Returns a NamespacedName of the owner given a UID
func (um *UIDMap) Get(key types.UID) (value types.NamespacedName, ok bool) {
um.mutex.RLock()
defer um.mutex.RUnlock()
value, ok = um.internal[key]
return value, ok
}

// Delete - Deletes associated UID to NamespacedName mapping
func (um *UIDMap) Delete(key types.UID) {
um.mutex.Lock()
defer um.mutex.Unlock()
delete(um.internal, key)
}

// Store - Adds a new UID to NamespacedName mapping
func (um *UIDMap) Store(key types.UID, value types.NamespacedName) {
um.mutex.Lock()
defer um.mutex.Unlock()
um.internal[key] = value
}
8 changes: 7 additions & 1 deletion pkg/ansible/proxy/kubeconfig/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,19 @@ type values struct {
Namespace string
}

type NamespacedOwnerReference struct {
metav1.OwnerReference
Namespace string
}

// Create renders a kubeconfig template and writes it to disk
func Create(ownerRef metav1.OwnerReference, proxyURL string, namespace string) (*os.File, error) {
nsOwnerRef := NamespacedOwnerReference{OwnerReference: ownerRef, Namespace: namespace}
parsedURL, err := url.Parse(proxyURL)
if err != nil {
return nil, err
}
ownerRefJSON, err := json.Marshal(ownerRef)
ownerRefJSON, err := json.Marshal(nsOwnerRef)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 1d3aa60

Please sign in to comment.