Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openstack: add simple test for the openstack-populator #668

Merged
merged 3 commits into from
Dec 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion cmd/openstack-populator/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
load(
"@io_bazel_rules_docker//container:container.bzl",
"container_image",
Expand Down Expand Up @@ -31,3 +31,9 @@ container_image(
files = [":openstack-populator"],
visibility = ["//visibility:public"],
)

go_test(
name = "openstack-populator_test",
srcs = ["openstack-populator_test.go"],
embed = [":openstack-populator_lib"],
)
50 changes: 21 additions & 29 deletions cmd/openstack-populator/openstack-populator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"io"
"net/http"
"os"
"path/filepath"
"strings"
"time"

Expand Down Expand Up @@ -60,17 +59,14 @@ func populate(fileName, identityEndpoint, secretName, imageID string) {
klog.Info("Prometheus progress counter registered.")
}

options, err := readOptions()
if err != nil {
klog.Fatal(err)
}
options := readOptions()

client := &libclient.Client{
URL: identityEndpoint,
Options: options,
}

err = client.Connect()
err := client.Connect()
if err != nil {
klog.Fatal(err)
}
Expand Down Expand Up @@ -143,34 +139,30 @@ func writeData(reader io.ReadCloser, file *os.File, imageID string, progress *pr
return nil
}

func readOptions() (options map[string]string, err error) {
func readOptions() (options map[string]string) {
options = map[string]string{}
secretDirPath := "/etc/secret-volume"
dirEntries, err := os.ReadDir(secretDirPath)
if err != nil {
return

// List of options to read from environment variables
envOptions := []string{
"regionName", "authType", "username", "userID", "password",
"applicationCredentialID", "applicationCredentialName", "applicationCredentialSecret",
"token", "systemScope", "projectName", "projectID", "userDomainName",
"userDomainID", "projectDomainName", "projectDomainID", "domainName",
"domainID", "defaultDomain", "insecureSkipVerify", "cacert", "availability",
}

klog.Info("Options:")
for _, dirEntry := range dirEntries {
if !dirEntry.Type().IsDir() {
option := dirEntry.Name()
if strings.HasPrefix(option, "..") {
continue
}
filePath := filepath.Join(secretDirPath, option)
var fileContent []byte
fileContent, err = os.ReadFile(filePath)
if err != nil {
return
}
value := string(fileContent)
options[option] = value
if option == "password" || option == "applicationCredentialSecret" || option == "token" {
value = strings.Repeat("*", len(value))
}
klog.Info(" - ", option, " = ", value)
for _, option := range envOptions {
value := os.Getenv(option)
options[option] = value

// Mask sensitive information
if option == "password" || option == "applicationCredentialSecret" || option == "token" {
value = strings.Repeat("*", len(value))
}

klog.Info(" - ", option, " = ", value)
}

return
}
171 changes: 171 additions & 0 deletions cmd/openstack-populator/openstack-populator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package main

import (
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"os"
"testing"
)

func setupMockServer() (*httptest.Server, string, int, error) {
listener, err := net.Listen("tcp", ":0")
if err != nil {
return nil, "", 0, err
}

mux := http.NewServeMux()

port := listener.Addr().(*net.TCPAddr).Port
baseURL := fmt.Sprintf("http://localhost:%d", port)

mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
response := fmt.Sprintf(`{
"versions": {
"values": [
{
"id": "v3.0",
"links": [
{"rel": "self", "href": "%s/v3/"}
],
"status": "stable"
}
]
}
}`, baseURL)
fmt.Fprint(w, response)
})

mux.HandleFunc("/v2/images/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `mock_data`)
})

mux.HandleFunc("/v3/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Subject-Token", "MIIFvgY")
w.WriteHeader(http.StatusCreated)
identityServer := fmt.Sprintf("%s/v3/", baseURL)
imageServiceURL := fmt.Sprintf("%s/v2/images", baseURL)
fmt.Println("identityServer ", identityServer)
response := fmt.Sprintf(`{
"token": {
"methods": ["password"],
"project": {
"domain": {
"id": "default",
"name": "Default"
},
"id": "8538a3f13f9541b28c2620eb19065e45",
"name": "admin"
},
"catalog": [
{
"type": "identity",
"name": "keystone",
"endpoints": [
{
"url": "%s",
"region": "RegionOne",
"interface": "public",
"id": "identity-public-endpoint-id"
},
{
"url": "%s",
"region": "RegionOne",
"interface": "admin",
"id": "identity-admin-endpoint-id"
},
{
"url": "%s",
"region": "RegionOne",
"interface": "internal",
"id": "identity-internal-endpoint-id"
}
]
},
{
"type": "image",
"name": "glance",
"endpoints": [
{
"url": "%s",
"region": "RegionOne",
"interface": "public",
"id": "image-public-endpoint-id"
}
]
}
],
"user": {
"domain": {
"id": "default",
"name": "Default"
},
"id": "3ec3164f750146be97f21559ee4d9c51",
"name": "admin"
},
"issued_at": "201406-10T20:55:16.806027Z"
}
}`,
identityServer,
identityServer,
identityServer,
imageServiceURL)

fmt.Fprint(w, response)
})

server := httptest.NewUnstartedServer(mux)
server.Listener = listener

server.Start()

return server, baseURL, port, nil
}

func TestPopulate(t *testing.T) {
os.Setenv("username", "testuser")
os.Setenv("password", "testpassword")
os.Setenv("projectName", "Default")
os.Setenv("domainName", "Default")
os.Setenv("insecureSkipVerify", "true")
os.Setenv("availability", "public")
os.Setenv("regionName", "RegionOne")
os.Setenv("authType", "password")

server, identityServerURL, port, err := setupMockServer()
if err != nil {
t.Fatalf("Failed to start mock server: %v", err)
}
defer server.Close()

fmt.Printf("Mock server running on port: %d\n", port)

fileName := "disk.img"
secretName := "test-secret"
imageID := "test-image-id"

fmt.Println("server ", identityServerURL)
populate(fileName, identityServerURL, secretName, imageID)

file, err := os.Open(fileName)
if err != nil {
t.Fatalf("Failed to open file: %v", err)
}
defer file.Close() // Ensure the file is closed after reading

content, err := io.ReadAll(file)
if err != nil {
t.Fatalf("Failed to read file: %v", err)
}

if string(content) != "mock_data\n" {
t.Errorf("Expected %s, got %s", "mock_data", string(content))
}

os.Remove(fileName)
}
43 changes: 10 additions & 33 deletions cmd/ovirt-populator/ovirt-populator.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,50 +156,27 @@ func populate(engineURL, diskID, volPath string) {
}

func loadEngineConfig(engineURL string) engineConfig {
user, err := os.ReadFile("/etc/secret-volume/user")
if err != nil {
klog.Fatal(err.Error())
}
pass, err := os.ReadFile("/etc/secret-volume/password")
if err != nil {
klog.Fatal(err.Error())
}
user := os.Getenv("user")
pass := os.Getenv("password")

var insecureSkipVerify []byte
_, err = os.Stat("/etc/secret-volume/insecureSkipVerify")
if err != nil {
if errors.Is(err, os.ErrNotExist) {
insecureSkipVerify = []byte("false")
} else {
klog.Fatal(err.Error())
}
} else {
insecureSkipVerify, err = os.ReadFile("/etc/secret-volume/insecureSkipVerify")
if err != nil {
klog.Fatal(err.Error())
}
insecureSkipVerify, found := os.LookupEnv("insecureSkipVerify")
if !found {
insecureSkipVerify = "false"
}

insecure, err := strconv.ParseBool(string(insecureSkipVerify))
if err != nil {
klog.Fatal(err.Error())
}

//If the insecure option is set, the ca file field in the secret is not required.
var cacert []byte
if insecure {
cacert = []byte("")
} else {
cacert, err = os.ReadFile("/etc/secret-volume/cacert")
if err != nil {
klog.Error(err.Error())
}
}
cacert := os.Getenv("cacert")

return engineConfig{
URL: engineURL,
username: string(user),
password: string(pass),
cacert: string(cacert),
username: user,
password: pass,
cacert: cacert,
insecure: insecure,
}
}
23 changes: 10 additions & 13 deletions pkg/lib-volume-populator/populator-machinery/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -628,11 +628,7 @@ func (c *controller) syncPvc(ctx context.Context, key, pvcNamespace, pvcName str
},
}
}
con.VolumeMounts = append(con.VolumeMounts, corev1.VolumeMount{
liranr23 marked this conversation as resolved.
Show resolved Hide resolved
Name: "secret-volume",
ReadOnly: true,
MountPath: "/etc/secret-volume",
})

if waitForFirstConsumer {
pod.Spec.NodeName = nodeName
}
Expand Down Expand Up @@ -940,6 +936,15 @@ func makePopulatePodSpec(pvcPrimeName, secretName string) corev1.PodSpec {
Drop: []corev1.Capability{"ALL"},
},
},
EnvFrom: []corev1.EnvFromSource{
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretName,
},
},
},
},
},
},
SecurityContext: &corev1.PodSecurityContext{
Expand All @@ -958,14 +963,6 @@ func makePopulatePodSpec(pvcPrimeName, secretName string) corev1.PodSpec {
},
},
},
{
Name: "secret-volume",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: secretName,
},
},
},
},
}
}
Expand Down
Loading