Skip to content

Commit 1579fe2

Browse files
dymurrayShawn Hurley
authored andcommitted
commands/up/local; pkg/ansible; Add support for up local to Ansible Operator (#569)
This PR includes a bump in `controller-runtime` to `0.1.4`. Without it I was seeing an error: ``` 2018/10/03 15:00:26 no kind "MemcachedList" is registered for version "cache.example.com/v1alpha1" ```
1 parent fa97d78 commit 1579fe2

File tree

7 files changed

+153
-20
lines changed

7 files changed

+153
-20
lines changed

Gopkg.lock

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@
2828

2929
[[constraint]]
3030
name = "sigs.k8s.io/controller-runtime"
31-
version = "v0.1.3"
31+
version = "v0.1.4"

commands/operator-sdk/cmd/cmdutil/util.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,17 @@ import (
2929
yaml "gopkg.in/yaml.v2"
3030
)
3131

32-
const configYaml = "./config/config.yaml"
33-
const tmpDockerfile = "./tmp/build/Dockerfile"
32+
type OperatorType int
33+
34+
const (
35+
configYaml = "./config/config.yaml"
36+
gopkgToml = "./Gopkg.toml"
37+
tmpDockerfile = "./tmp/build/Dockerfile"
38+
)
39+
const (
40+
OperatorTypeGo OperatorType = iota
41+
OperatorTypeAnsible
42+
)
3443

3544
// MustInProjectRoot checks if the current dir is the project root.
3645
func MustInProjectRoot() {
@@ -74,3 +83,15 @@ func GetCurrPkg() string {
7483
currPkg := strings.Replace(wd, goSrc+string(filepath.Separator), "", 1)
7584
return currPkg
7685
}
86+
87+
// GetOperatorType returns type of operator is in cwd
88+
// This function should be called after verifying the user is in project root
89+
// e.g: "go", "ansible"
90+
func GetOperatorType() OperatorType {
91+
// Assuming that if Gopkg.toml exists then this is a Go operator
92+
_, err := os.Stat(gopkgToml)
93+
if err != nil && os.IsNotExist(err) {
94+
return OperatorTypeAnsible
95+
}
96+
return OperatorTypeGo
97+
}

commands/operator-sdk/cmd/up/local.go

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,26 @@ package up
1616

1717
import (
1818
"fmt"
19+
"log"
1920
"os"
2021
"os/exec"
2122
"os/signal"
2223
"os/user"
2324
"path/filepath"
25+
"runtime"
2426
"strings"
2527
"syscall"
2628

2729
"github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd/cmdutil"
2830
cmdError "github.com/operator-framework/operator-sdk/commands/operator-sdk/error"
31+
ansibleOperator "github.com/operator-framework/operator-sdk/pkg/ansible/operator"
32+
proxy "github.com/operator-framework/operator-sdk/pkg/ansible/proxy"
2933
"github.com/operator-framework/operator-sdk/pkg/util/k8sutil"
30-
34+
sdkVersion "github.com/operator-framework/operator-sdk/version"
35+
"github.com/sirupsen/logrus"
3136
"github.com/spf13/cobra"
37+
"sigs.k8s.io/controller-runtime/pkg/client/config"
38+
"sigs.k8s.io/controller-runtime/pkg/manager"
3239
)
3340

3441
func NewLocalCmd() *cobra.Command {
@@ -66,8 +73,15 @@ const (
6673
func upLocalFunc(cmd *cobra.Command, args []string) {
6774
mustKubeConfig()
6875
cmdutil.MustInProjectRoot()
69-
c := cmdutil.GetConfig()
70-
upLocal(c.ProjectName)
76+
switch cmdutil.GetOperatorType() {
77+
case cmdutil.OperatorTypeGo:
78+
c := cmdutil.GetConfig()
79+
upLocal(c.ProjectName)
80+
case cmdutil.OperatorTypeAnsible:
81+
upLocalAnsible()
82+
default:
83+
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to determine operator type"))
84+
}
7185
}
7286

7387
// mustKubeConfig checks if the kubeconfig file exists.
@@ -112,3 +126,37 @@ func upLocal(projectName string) {
112126
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to run operator locally: %v", err))
113127
}
114128
}
129+
130+
func upLocalAnsible() {
131+
mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{Namespace: namespace})
132+
if err != nil {
133+
log.Fatal(err)
134+
}
135+
136+
printVersion()
137+
done := make(chan error)
138+
139+
// start the proxy
140+
proxy.RunProxy(done, proxy.Options{
141+
Address: "localhost",
142+
Port: 8888,
143+
KubeConfig: mgr.GetConfig(),
144+
})
145+
146+
// start the operator
147+
go ansibleOperator.Run(done, mgr, namespace)
148+
149+
// wait for either to finish
150+
err = <-done
151+
if err == nil {
152+
logrus.Info("Exiting")
153+
} else {
154+
logrus.Fatal(err.Error())
155+
}
156+
}
157+
158+
func printVersion() {
159+
logrus.Infof("Go Version: %s", runtime.Version())
160+
logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)
161+
logrus.Infof("operator-sdk Version: %v", sdkVersion.Version)
162+
}

pkg/ansible/controller/controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func Add(mgr manager.Manager, options Options) {
8080
log.Fatal(err)
8181
}
8282

83-
r := NewReconcileLoop(time.Minute*1, options.GVK, mgr.GetClient())
83+
r := NewReconcileLoop(time.Minute*1, options.GVK, mgr.GetClient(), options.Namespace)
8484
r.Stop = options.StopChannel
8585
cs := &source.Channel{Source: r.Source}
8686
cs.InjectStopChannel(options.StopChannel)

pkg/ansible/controller/source.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,25 @@ import (
2727

2828
// ReconcileLoop - new loop
2929
type ReconcileLoop struct {
30-
Source chan event.GenericEvent
31-
Stop <-chan struct{}
32-
GVK schema.GroupVersionKind
33-
Interval time.Duration
34-
Client client.Client
30+
Source chan event.GenericEvent
31+
Stop <-chan struct{}
32+
GVK schema.GroupVersionKind
33+
Interval time.Duration
34+
Client client.Client
35+
Namespace string
3536
}
3637

3738
// NewReconcileLoop - loop for a GVK.
3839
// The reconcilation loop is needed because the resync period
3940
// for the informer is not suitable for this use case.
40-
func NewReconcileLoop(interval time.Duration, gvk schema.GroupVersionKind, c client.Client) ReconcileLoop {
41+
func NewReconcileLoop(interval time.Duration, gvk schema.GroupVersionKind, c client.Client, namespace string) ReconcileLoop {
4142
s := make(chan event.GenericEvent, 1025)
4243
return ReconcileLoop{
43-
Source: s,
44-
GVK: gvk,
45-
Interval: interval,
46-
Client: c,
44+
Source: s,
45+
GVK: gvk,
46+
Interval: interval,
47+
Client: c,
48+
Namespace: namespace,
4749
}
4850
}
4951

@@ -57,7 +59,9 @@ func (r *ReconcileLoop) Start() {
5759
case <-ticker.C:
5860
// List all object for the GVK
5961
ul := &unstructured.UnstructuredList{}
62+
lo := client.ListOptions{}
6063
ul.SetGroupVersionKind(r.GVK)
64+
lo.InNamespace(r.Namespace)
6165
err := r.Client.List(context.Background(), nil, ul)
6266
if err != nil {
6367
logrus.Warningf("unable to list resources for GV: %v during reconcilation", r.GVK)

pkg/ansible/operator/operator.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2018 The Operator-SDK Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package operator
16+
17+
import (
18+
"log"
19+
"math/rand"
20+
"time"
21+
22+
"github.com/operator-framework/operator-sdk/pkg/ansible/controller"
23+
"github.com/operator-framework/operator-sdk/pkg/ansible/runner"
24+
"sigs.k8s.io/controller-runtime/pkg/manager"
25+
"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
26+
27+
"github.com/sirupsen/logrus"
28+
)
29+
30+
// Run - A blocking function which starts a controller-runtime manager
31+
// It starts an Operator by reading in the values in `./watches.yaml`, adds a controller
32+
// to the manager, and finally running the manager.
33+
func Run(done chan error, mgr manager.Manager, namespace string) {
34+
if namespace == "" {
35+
namespace = "default"
36+
}
37+
watches, err := runner.NewFromWatches("./watches.yaml")
38+
if err != nil {
39+
logrus.Error("Failed to get watches")
40+
done <- err
41+
return
42+
}
43+
rand.Seed(time.Now().Unix())
44+
c := signals.SetupSignalHandler()
45+
46+
for gvk, runner := range watches {
47+
controller.Add(mgr, controller.Options{
48+
GVK: gvk,
49+
Namespace: namespace,
50+
Runner: runner,
51+
StopChannel: c,
52+
})
53+
}
54+
log.Fatal(mgr.Start(c))
55+
done <- nil
56+
}

0 commit comments

Comments
 (0)