Skip to content

Commit

Permalink
Add minikube option to quickstart plugin (#44)
Browse files Browse the repository at this point in the history
* adding minikube option to quickstart plugin

* removing clutter, making version check < instead of ==

* cleanup

* more cleanup

* 3 CPUs for minikube

* typo

* timing install, finished message

* password prompting on mac

* adding message for setting minikube driver
  • Loading branch information
psschwei authored Sep 27, 2021
1 parent f346b0c commit ae7395e
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 5 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ After the plugin is installed, you can use `kn quickstart` to run its related su
## Usage

```
Get up and running with a local Knative environment running on KinD.
Get up and running with a local Knative environment
Usage:
kn-quickstart [command]
Expand All @@ -30,6 +30,7 @@ Available Commands:
completion generate the autocompletion script for the specified shell
help Help about any command
kind Quickstart with Kind
minikube Quickstart with Minikube
version Prints the plugin version
Flags:
Expand All @@ -46,6 +47,14 @@ Set up a local Knative cluster using [KinD](https://kind.sigs.k8s.io/):
kn quickstart kind
```

### Quickstart with Minikube

Set up a local Knative cluster using [Minikube](https://minikube.sigs.k8s.io/):

```bash
kn quickstart minikube
```

## Building from Source

You must [set up your development environment](https://github.com/knative/client/blob/master/docs/DEVELOPMENT.md#prerequisites) before you build `kn-plugin-quickstart`.
Expand All @@ -57,3 +66,4 @@ git clone [email protected]:knative-sandbox/kn-plugin-quickstart.git
cd kn-plugin-quickstart
./hack/build.sh
```

2 changes: 1 addition & 1 deletion internal/command/kind.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"knative.dev/kn-plugin-quickstart/pkg/kind"
)

// NewKindCommand implements 'kn kind' command
// NewKindCommand implements 'kn quickstart kind' command
func NewKindCommand() *cobra.Command {
return &cobra.Command{
Use: "kind",
Expand Down
35 changes: 35 additions & 0 deletions internal/command/minikube.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright © 2021 The Knative 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 command

import (
"fmt"

"knative.dev/kn-plugin-quickstart/pkg/minikube"

"github.com/spf13/cobra"
)

// NewMinikubeCommand implements 'kn quickstart minikube' command
func NewMinikubeCommand() *cobra.Command {
return &cobra.Command{
Use: "minikube",
Short: "Quickstart with Minikube",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println("Running Knative Quickstart using Minikube")
return minikube.SetUp()
},
}
}
5 changes: 3 additions & 2 deletions internal/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ import (
"knative.dev/kn-plugin-quickstart/internal/command"
)

// NewSourceKafkaCommand represents the plugin's entrypoint
// NewRootCommand represents the plugin's entrypoint
func NewRootCommand() *cobra.Command {

var rootCmd = &cobra.Command{
Use: "kn-quickstart",
Short: "Get started quickly with Knative",
Long: `Get up and running with a local Knative environment running on KinD.`,
Long: `Get up and running with a local Knative environment`,
}

rootCmd.AddCommand(command.NewKindCommand())
rootCmd.AddCommand(command.NewMinikubeCommand())
rootCmd.AddCommand(command.NewVersionCommand())

return rootCmd
Expand Down
32 changes: 31 additions & 1 deletion pkg/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ func Kourier() error {
}
fmt.Println(" Ingress patched...")

fmt.Println(" Finished installing Kourier Networking layer")

return nil
}

// KourierKind runs the kind-specific setup for Kourier
func KourierKind() error {
fmt.Println("🕸 Configuring Kourier for Kind...")

config := `apiVersion: v1
kind: Service
metadata:
Expand Down Expand Up @@ -76,9 +85,30 @@ spec:
return fmt.Errorf("domain dns: %w", err)
}
fmt.Println(" Domain DNS set up...")
fmt.Println(" Finished configuring Kourier")

fmt.Println(" Finished installing Kourier Networking layer")
return nil
}

// KourierMinikube runs the minikube-specific setup for Kourier
func KourierMinikube() error {
fmt.Println("🕸 Configuring Kourier for Minikube...")

if err := retryingApply("https://github.com/knative/serving/releases/download/v" + servingVersion + "/serving-default-domain.yaml"); err != nil {
return fmt.Errorf("default domain: %w", err)
}
if err := waitForPodsReady("knative-serving"); err != nil {
return fmt.Errorf("core: %w", err)
}

fmt.Println(" Domain DNS set up...")

tunnel := exec.Command("minikube", "tunnel", "--profile", "minikube-knative")
if err := tunnel.Start(); err != nil {
return fmt.Errorf("tunnel: %w", err)
}
fmt.Println(" Minikube tunnel...")
fmt.Println(" Finished configuring Kourier")
return nil
}

Expand Down
3 changes: 3 additions & 0 deletions pkg/kind/kind.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func SetUp() error {
if err := install.Kourier(); err != nil {
return fmt.Errorf("install kourier: %w", err)
}
if err := install.KourierKind(); err != nil {
return fmt.Errorf("configure kourier: %w", err)
}
if err := install.Eventing(); err != nil {
return fmt.Errorf("install eventing: %w", err)
}
Expand Down
186 changes: 186 additions & 0 deletions pkg/minikube/minikube.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// Copyright © 2021 The Knative 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 minikube

import (
"fmt"
"os"
"os/exec"
"regexp"
"runtime"
"strconv"
"strings"
"time"

"knative.dev/kn-plugin-quickstart/pkg/install"
)

var clusterName = "minikube-knative"
var minikubeVersion = 1.23

// SetUp creates a local Minikube cluster and installs all the relevant Knative components
func SetUp() error {
start := time.Now()

if runtime.GOOS == "darwin" {
fmt.Println("NOTE: Using Minikube on Mac may require entering your password to enable networking.")
}

if err := createMinikubeCluster(); err != nil {
return fmt.Errorf("creating cluster: %w", err)
}
if err := install.Serving(); err != nil {
return fmt.Errorf("install serving: %w", err)
}
if err := install.Kourier(); err != nil {
return fmt.Errorf("install kourier: %w", err)
}
if err := install.KourierMinikube(); err != nil {
return fmt.Errorf("configure kourier: %w", err)
}
if err := install.Eventing(); err != nil {
return fmt.Errorf("install eventing: %w", err)
}
finish := time.Since(start).Round(time.Second)
fmt.Printf("🚀 Knative install took: %s \n", finish)
fmt.Println("🎉 Now have some fun with Serverless and Event Driven Apps!")
return nil
}

func createMinikubeCluster() error {
if err := checkMinikubeVersion(); err != nil {
return fmt.Errorf("minikube version: %w", err)
}
if err := checkForExistingCluster(); err != nil {
return fmt.Errorf("existing cluster: %w", err)
}
return nil
}

// checkMinikubeVersion validates that the user has the correct version of Minikube installed.
// If not, it prompts the user to download a newer version before continuing.
func checkMinikubeVersion() error {
versionCheck := exec.Command("minikube", "version", "--short")
out, err := versionCheck.CombinedOutput()
if err != nil {
return fmt.Errorf("minikube version: %w", err)
}
fmt.Printf("Minikube version is: %s\n", string(out))

userMinikubeVersion, err := parseMinikubeVersion(string(out))
if err != nil {
return fmt.Errorf("parsing minikube version: %w", err)
}
if userMinikubeVersion < minikubeVersion {
var resp string
fmt.Printf("WARNING: We require at least Minikube v%.2f, while you are using v%.2f\n", minikubeVersion, userMinikubeVersion)
fmt.Println("You can download a newer version from https://github.com/kubernetes/minikube/releases/")
fmt.Print("Continue anyway? (not recommended) [y/N]: ")
fmt.Scanf("%s", &resp)
if strings.ToLower(resp) != "y" {
fmt.Println("Installation stopped. Please upgrade minikube and run again")
os.Exit(0)
}
}

return nil
}

// checkForExistingCluster checks if the user already has a Minikube cluster. If so, it provides
// the option of deleting the existing cluster and recreating it. If not, it proceeds to
// creating a new cluster
func checkForExistingCluster() error {

getClusters := exec.Command("minikube", "profile", "list")
out, err := getClusters.CombinedOutput()
if err != nil {
// there are no existing minikube profiles, the listing profiles command will error
// if there were no profiles, we simply want to create a new one and not stop the install
// so if the error is the "MK_USAGE_NO_PROFILE" error, we ignore it and continue onwards
if !strings.Contains(string(out), "MK_USAGE_NO_PROFILE") {
return fmt.Errorf("check cluster: %w", err)
}
}
// TODO Add tests for regex
r := regexp.MustCompile(clusterName)
matches := r.Match(out)
if matches {
var resp string
fmt.Print("Knative Cluster " + clusterName + " already installed.\nDelete and recreate [y/N]: ")
fmt.Scanf("%s", &resp)
if strings.ToLower(resp) != "y" {
fmt.Println("Installation skipped")
return nil
}
fmt.Println("deleting cluster...")
deleteCluster := exec.Command("minikube", "delete", "--profile", clusterName)
if err := deleteCluster.Run(); err != nil {
return fmt.Errorf("delete cluster: %w", err)
}
if err := createNewCluster(); err != nil {
return fmt.Errorf("new cluster: %w", err)
}
}

if err := createNewCluster(); err != nil {
return fmt.Errorf("new cluster: %w", err)
}

return nil
}

// createNewCluster creates a new Minikube cluster
func createNewCluster() error {

fmt.Println("☸ Creating Minikube cluster...")
fmt.Println("\n By default, using the standard minikube driver for your system")
fmt.Println("If you wish to use a different driver, please configure minikube using")
fmt.Println(" minikube config set --driver <your-driver>")

// create cluster and wait until ready
createCluster := exec.Command("minikube", "start", "--cpus", "3", "--profile", clusterName, "--wait", "all")
if err := runCommand(createCluster); err != nil {
return fmt.Errorf("minikube create: %w", err)
}

// minikube tunnel
tunnel := exec.Command("minikube", "tunnel", "--profile", "minikube-knative")
if err := tunnel.Start(); err != nil {
return fmt.Errorf("tunnel: %w", err)
}
fmt.Println(" Minikube tunnel...")

fmt.Println(" Cluster ready")
return nil
}

func runCommand(c *exec.Cmd) error {
if out, err := c.CombinedOutput(); err != nil {
fmt.Println(string(out))
return err
}
return nil
}

func parseMinikubeVersion(v string) (float64, error) {
strippedVersion := strings.TrimLeft(strings.TrimRight(v, "\n"), "v")
dotVersion := strings.Split(strippedVersion, ".")
floatVersion, err := strconv.ParseFloat(dotVersion[0]+"."+dotVersion[1], 64)
if err != nil {
return 0, err
}

return floatVersion, nil
}

0 comments on commit ae7395e

Please sign in to comment.