Repository: topolvm/topolvm
Pull request #840 (2024-02-08 09:11:44)

Change directory tree to the new kubebilder template
a part of: https://github.com/topolvm/topolvm/issues/760
ref: https://book.kubebuilder.io/migration/migration_guide_gov3_to_gov4

llamerada-jp: @jakobmoellerdev 
We can move the necessary directories under the pkg or top dir. Is the lvm-operator all of the controller dir required? Or specific constants or interface definitions?
jakobmoellerdev: Thanks, we appreciate you modifying the current approach:

These are all the usages in lvm-operator of any topolvm package as of now:

- `github.com/topolvm/topolvm/lvmd` (used for config parsing, elements such as DeviceClass or ThinPool)
- `github.com/topolvm/topolvm/pkg/lvmd/cmd` (used for config parsing)
- `github.com/topolvm/topolvm/api/v1` (used for CR interaction via k8s client)
- `github.com/topolvm/topolvm/controllers` (used to start the TopoLVM controllers embedded with custom settings for things like leader election)
- `github.com/topolvm/topolvm/driver` (to start the CSI gRPC identity and controller server)
- `github.com/topolvm/topolvm/client` (to configure the controllers of github.com/topolvm/topolvm/controllers canonically)
- `github.com/topolvm/topolvm/lvmd/command` (to set the Containerized flag)
- `github.com/topolvm/topolvm/runners` (to configure the metrics exporter embedded)
llamerada-jp: @jakobmoellerdev 

In the last commit of this PR, the functions used from lvm-operator are put in the pkg dir.
1. Is this implementation way ok?
1. I have put all the functions used in lvm-operator in the pkg. I would like you to check if anything is missing.
1. The client package should not be needed if lvm-operator does not support the legacy CR (logicalvolumes.topolvm.cybozu.com). Is it necessary?
jakobmoellerdev: Ill pull your branch and do a temporary recompile to see if we have any incompatibilities. Please give me some time to confirm, will report ASAP.
jakobmoellerdev: Okay so maybe my Feedback here:

I think this will work (at least my compile didnt go crazy, but I may have to open up follow up issues if there is in the future any type that would need to be exported (something we can do though and not blocking this PR)

However, I think the passing of internal to pkg (via aliasing of a pkg type into the internal pacakge) to expose the types is quite convoluted and makes the code harder to maintain. I'm wondering why it is necessary for us to adopt "internal" over pkg, since we have no sensitive code that is not "allowed" to be imported. Why is it a must have for us to adopt this suggested build pattern from kubebuilder v4?
jakobmoellerdev: > When adding a new controller or modules, kubeuilder generates a skeleton in the specific directory. So we were going to do this code migration to ease future development.

I understand the incentive but the only alternative for us is to use the commands as is which prohibits us from starting the controllers within the same controller manager. Thus we need direct access to the Controller structs

> We'll keep pkg dir for now. However, we don't expect the code under this directory to be used for other projects and want to do this migration in the future. Could you modify lvm-operator to remove the dependency on this directory and let us know if it's done?

I'm not certain how this would ever work out for us (and we cannot migrate unless you change your package structures anyway in main, since we depend on the latest topolvm code). We just recently switched to a model where we incorporated all the controllers directly because of resource constraints: Starting the controllers like in https://github.com/openshift/lvm-operator/blob/main/cmd/vgmanager/vgmanager.go#L153-L196 is currently only possible via go import.

If there is a way to do this without actually importing the code from these packages, Im open to this of course. We could for example change the way that the topolvm cmd package is started because this is non-standard kubebuilder. If we find a way to incorporate the manager into this then I believe this can solve our issue. 


jakobmoellerdev: Maybe let me summarize: I am not opposed to this change (its always good to stick to upstream), but I also dont think that moving the controllers into internal is really a must-enforce. Kubebuilder does a suggested layout like this because most controllers actually nowadays are downstream controllers that do not need to have controllers exposed.
llamerada-jp: @jakobmoellerdev 
Thank you for your comment.
TopoLVM's modules were not designed to be referenced from the outside. By limiting the interface to pkg, I expect to notice when the interface definition is changed. Because so, for this PR, I want to proceed with putting interfaces in the pkg dir. If I come up with a better way or if we need to change the interface in the future, we'll make another PR.
satoru-takeuchi: @llamerada-jp Could you add [this link](https://book.kubebuilder.io/migration/migration_guide_gov3_to_gov4) to the PR description and the description in the following commit?

> Change directory tree to the new kubebilder template

In addition, how about adding [this link](https://github.com/topolvm/topolvm/pull/840#issuecomment-1963539834) to the following commits?

> make interfaces to be used externally

I believe that both links will help us very much to understand why we made these changes.

Patch:
diff --git a/.dockerignore b/.dockerignore
index f4685c85..8f052cfa 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -7,7 +7,7 @@ charts/
 config/
 deploy/
 docs/
-e2e/
 example/
 include/
+test/
 testbin/
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index c1b7da85..0d6d1f62 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -28,7 +28,6 @@ jobs:
       - run: make check-uncommitted
       - run: make test
       - run: make groupname-test
-      - run: sudo -E env PATH=${PATH} go test -count=1 -race -v ./lvmd ./driver ./filesystem
 
   build-images:
     name: "build-images"
diff --git a/.gitignore b/.gitignore
index 2e81ff38..cea4c1ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,9 +28,9 @@ Dockerfile.cross
 # ignore tools
 /bin
 /build
-/e2e/build
-/e2e/tmpbin
 /include
+/test/e2e/build
+/test/e2e/tmpbin
 /testbin
 
 # ignore unneeded generated configs
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7e667476..6cf67912 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,13 +1,14 @@
 # Contributing Guide
 
-- [Ways to Contribute](#ways-to-contribute)
-- [Find an Issue](#find-an-issue)
-- [Ask for Help](#ask-for-help)
-- [Pull Request Lifecycle](#pull-request-lifecycle)
-- [Development Environment Setup](#development-environment-setup)
-- [Sign Your Commits](#sign-your-commits)
-  - [DCO](#dco)
-- [Pull Request Checklist](#pull-request-checklist)
+- [Contributing Guide](#contributing-guide)
+  - [Ways to Contribute](#ways-to-contribute)
+  - [Find an Issue](#find-an-issue)
+  - [Ask for Help](#ask-for-help)
+  - [Pull Request Lifecycle](#pull-request-lifecycle)
+  - [Development Environment Setup](#development-environment-setup)
+  - [Sign Your Commits](#sign-your-commits)
+    - [DCO](#dco)
+  - [Pull Request Checklist](#pull-request-checklist)
 
 Welcome! We are glad that you want to contribute to our project!
 
@@ -100,7 +101,7 @@ we suggest preparing a dedicated physical or virtual machine.
     make test
 
     # for end-to-end test
-    cd e2e
+    cd test/e2e
     make start-lvmd
     make test
     ```
diff --git a/Dockerfile b/Dockerfile
index 9dba5462..fe820a42 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,7 +8,7 @@ ARG TARGETARCH
 COPY . /workdir
 WORKDIR /workdir
 
-RUN touch lvmd/proto/*.go
+RUN touch pkg/lvmd/proto/*.go
 RUN make build-topolvm TOPOLVM_VERSION=${TOPOLVM_VERSION} GOARCH=${TARGETARCH}
 
 # TopoLVM container
diff --git a/Makefile b/Makefile
index 12b80509..27d8d789 100644
--- a/Makefile
+++ b/Makefile
@@ -72,16 +72,16 @@ help: ## Display this help.
 
 ##@ Development
 
-lvmd/proto/lvmd.pb.go: lvmd/proto/lvmd.proto
+pkg/lvmd/proto/lvmd.pb.go: pkg/lvmd/proto/lvmd.proto
 	$(PROTOC) --go_out=module=github.com/topolvm/topolvm:. $<
 
-lvmd/proto/lvmd_grpc.pb.go: lvmd/proto/lvmd.proto
+pkg/lvmd/proto/lvmd_grpc.pb.go: pkg/lvmd/proto/lvmd.proto
 	$(PROTOC) --go-grpc_out=module=github.com/topolvm/topolvm:. $<
 
-docs/lvmd-protocol.md: lvmd/proto/lvmd.proto
+docs/lvmd-protocol.md: pkg/lvmd/proto/lvmd.proto
 	$(PROTOC) --doc_out=./docs --doc_opt=markdown,$@ $<
 
-PROTOBUF_GEN = lvmd/proto/lvmd.pb.go lvmd/proto/lvmd_grpc.pb.go docs/lvmd-protocol.md
+PROTOBUF_GEN = pkg/lvmd/proto/lvmd.pb.go pkg/lvmd/proto/lvmd_grpc.pb.go docs/lvmd-protocol.md
 
 .PHONY: manifests
 manifests: generate-legacy-api ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
@@ -89,7 +89,7 @@ manifests: generate-legacy-api ## Generate WebhookConfiguration, ClusterRole and
 		crd:crdVersions=v1 \
 		rbac:roleName=topolvm-controller \
 		webhook \
-		paths="./api/...;./controllers;./hook;./driver/internal/k8s;./pkg/..." \
+		paths="./api/...;./internal/...;./cmd/..." \
 		output:crd:artifacts:config=config/crd/bases
 	cat config/crd/bases/topolvm.io_logicalvolumes.yaml | xargs -d"	" printf "$$CRD_TEMPLATE" > charts/topolvm/templates/crds/topolvm.io_logicalvolumes.yaml
 	cat config/crd/bases/topolvm.cybozu.com_logicalvolumes.yaml | xargs -d"	" printf "$$LEGACY_CRD_TEMPLATE" > charts/topolvm/templates/crds/topolvm.cybozu.com_logicalvolumes.yaml
@@ -138,7 +138,7 @@ groupname-test: ## Run unit tests that depends on the groupname.
 	go install ./...
 
 	mkdir -p $(ENVTEST_ASSETS_DIR)
-	source <($(BINDIR)/setup-envtest use $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p env); GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn TEST_LEGACY=true go test -count=1 -race -v --timeout=60s ./client/*
+	source <($(BINDIR)/setup-envtest use $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p env); GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn TEST_LEGACY=true go test -count=1 -race -v --timeout=60s ./internal/client/*
 	TEST_LEGACY=true go test -count=1 -race -v --timeout=60s ./constants*.go
 
 .PHONY: clean
@@ -160,11 +160,11 @@ build-topolvm: build/hypertopolvm build/lvmd
 
 build/hypertopolvm: $(GO_FILES)
 	mkdir -p build
-	GOARCH=$(GOARCH) go build -o $@ -ldflags "-w -s -X github.com/topolvm/topolvm.Version=$(TOPOLVM_VERSION)" ./pkg/hypertopolvm
+	GOARCH=$(GOARCH) go build -o $@ -ldflags "-w -s -X github.com/topolvm/topolvm.Version=$(TOPOLVM_VERSION)" ./cmd/hypertopolvm
 
 build/lvmd: $(GO_FILES)
 	mkdir -p build
-	GOARCH=$(GOARCH) CGO_ENABLED=0 go build -o $@ -ldflags "-w -s -X github.com/topolvm/topolvm.Version=$(TOPOLVM_VERSION)" ./pkg/lvmd
+	GOARCH=$(GOARCH) CGO_ENABLED=0 go build -o $@ -ldflags "-w -s -X github.com/topolvm/topolvm.Version=$(TOPOLVM_VERSION)" ./cmd/lvmd
 
 .PHONY: csi-sidecars
 csi-sidecars: ## Build sidecar binaries.
diff --git a/pkg/gencert/main.go b/cmd/gencert/main.go
similarity index 100%
rename from pkg/gencert/main.go
rename to cmd/gencert/main.go
diff --git a/pkg/hypertopolvm/main.go b/cmd/hypertopolvm/main.go
similarity index 76%
rename from pkg/hypertopolvm/main.go
rename to cmd/hypertopolvm/main.go
index 1f6eeebb..85a79d6b 100644
--- a/pkg/hypertopolvm/main.go
+++ b/cmd/hypertopolvm/main.go
@@ -5,10 +5,10 @@ import (
 	"os"
 	"path/filepath"
 
-	lvmd "github.com/topolvm/topolvm/pkg/lvmd/cmd"
-	controller "github.com/topolvm/topolvm/pkg/topolvm-controller/cmd"
-	node "github.com/topolvm/topolvm/pkg/topolvm-node/cmd"
-	scheduler "github.com/topolvm/topolvm/pkg/topolvm-scheduler/cmd"
+	lvmd "github.com/topolvm/topolvm/cmd/lvmd/app"
+	controller "github.com/topolvm/topolvm/cmd/topolvm-controller/app"
+	node "github.com/topolvm/topolvm/cmd/topolvm-node/app"
+	scheduler "github.com/topolvm/topolvm/cmd/topolvm-scheduler/app"
 )
 
 func usage() {
diff --git a/pkg/lvmd/cmd/config.go b/cmd/lvmd/app/config.go
similarity index 79%
rename from pkg/lvmd/cmd/config.go
rename to cmd/lvmd/app/config.go
index 59c1afcd..bc879ddb 100644
--- a/pkg/lvmd/cmd/config.go
+++ b/cmd/lvmd/app/config.go
@@ -1,11 +1,11 @@
-package cmd
+package app
 
 import (
 	"context"
 	"os"
 
 	"github.com/topolvm/topolvm"
-	"github.com/topolvm/topolvm/lvmd"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 	"sigs.k8s.io/yaml"
 )
@@ -15,9 +15,9 @@ type Config struct {
 	// SocketName is Unix domain socket name
 	SocketName string `json:"socket-name"`
 	// DeviceClasses is
-	DeviceClasses []*lvmd.DeviceClass `json:"device-classes"`
+	DeviceClasses []*lvmdTypes.DeviceClass `json:"device-classes"`
 	// LvcreateOptionClasses are classes that define options for the lvcreate command
-	LvcreateOptionClasses []*lvmd.LvcreateOptionClass `json:"lvcreate-option-classes"`
+	LvcreateOptionClasses []*lvmdTypes.LvcreateOptionClass `json:"lvcreate-option-classes"`
 }
 
 var config = &Config{
diff --git a/pkg/lvmd/cmd/health.go b/cmd/lvmd/app/health.go
similarity index 99%
rename from pkg/lvmd/cmd/health.go
rename to cmd/lvmd/app/health.go
index 6222b8b7..dd1de9ae 100644
--- a/pkg/lvmd/cmd/health.go
+++ b/cmd/lvmd/app/health.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"context"
diff --git a/pkg/lvmd/cmd/root.go b/cmd/lvmd/app/root.go
similarity index 93%
rename from pkg/lvmd/cmd/root.go
rename to cmd/lvmd/app/root.go
index e7337e15..21d45075 100644
--- a/pkg/lvmd/cmd/root.go
+++ b/cmd/lvmd/app/root.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"context"
@@ -13,9 +13,10 @@ import (
 
 	"github.com/spf13/cobra"
 	"github.com/topolvm/topolvm"
-	"github.com/topolvm/topolvm/lvmd"
-	"github.com/topolvm/topolvm/lvmd/command"
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/internal/lvmd"
+	"github.com/topolvm/topolvm/internal/lvmd/command"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/health/grpc_health_v1"
 	"k8s.io/klog/v2"
@@ -72,7 +73,7 @@ func subMain(ctx context.Context) error {
 			return err
 		}
 
-		if dc.Type == lvmd.TypeThin {
+		if dc.Type == lvmdTypes.TypeThin {
 			_, err = vg.FindPool(ctx, dc.ThinPoolConfig.Name)
 			if err != nil {
 				logger.Error(err, "Thin pool not found:", "thinpool", dc.ThinPoolConfig.Name)
diff --git a/cmd/lvmd/main.go b/cmd/lvmd/main.go
new file mode 100644
index 00000000..44213170
--- /dev/null
+++ b/cmd/lvmd/main.go
@@ -0,0 +1,7 @@
+package main
+
+import "github.com/topolvm/topolvm/cmd/lvmd/app"
+
+func main() {
+	app.Execute()
+}
diff --git a/pkg/topolvm-controller/cmd/root.go b/cmd/topolvm-controller/app/root.go
similarity index 99%
rename from pkg/topolvm-controller/cmd/root.go
rename to cmd/topolvm-controller/app/root.go
index a41c45e6..43296f91 100644
--- a/pkg/topolvm-controller/cmd/root.go
+++ b/cmd/topolvm-controller/app/root.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"flag"
diff --git a/pkg/topolvm-controller/cmd/run.go b/cmd/topolvm-controller/app/run.go
similarity index 91%
rename from pkg/topolvm-controller/cmd/run.go
rename to cmd/topolvm-controller/app/run.go
index b4ca2752..ee1b3abd 100644
--- a/pkg/topolvm-controller/cmd/run.go
+++ b/cmd/topolvm-controller/app/run.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"context"
@@ -10,11 +10,11 @@ import (
 	"github.com/topolvm/topolvm"
 	topolvmlegacyv1 "github.com/topolvm/topolvm/api/legacy/v1"
 	topolvmv1 "github.com/topolvm/topolvm/api/v1"
-	clientwrapper "github.com/topolvm/topolvm/client"
-	"github.com/topolvm/topolvm/controllers"
-	"github.com/topolvm/topolvm/driver"
-	"github.com/topolvm/topolvm/hook"
-	"github.com/topolvm/topolvm/runners"
+	clientwrapper "github.com/topolvm/topolvm/internal/client"
+	"github.com/topolvm/topolvm/internal/controller"
+	"github.com/topolvm/topolvm/internal/driver"
+	"github.com/topolvm/topolvm/internal/hook"
+	"github.com/topolvm/topolvm/internal/runners"
 	"google.golang.org/grpc"
 	storagev1 "k8s.io/api/storage/v1"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -99,13 +99,13 @@ func subMain() error {
 	}
 
 	// register controllers
-	nodecontroller := controllers.NewNodeReconciler(client, config.skipNodeFinalize)
+	nodecontroller := controller.NewNodeReconciler(client, config.skipNodeFinalize)
 	if err := nodecontroller.SetupWithManager(mgr); err != nil {
 		setupLog.Error(err, "unable to create controller", "controller", "Node")
 		return err
 	}
 
-	pvccontroller := controllers.NewPersistentVolumeClaimReconciler(client, apiReader)
+	pvccontroller := controller.NewPersistentVolumeClaimReconciler(client, apiReader)
 	if err := pvccontroller.SetupWithManager(mgr); err != nil {
 		setupLog.Error(err, "unable to create controller", "controller", "PersistentVolumeClaim")
 		return err
diff --git a/cmd/topolvm-controller/main.go b/cmd/topolvm-controller/main.go
new file mode 100644
index 00000000..0ead77c2
--- /dev/null
+++ b/cmd/topolvm-controller/main.go
@@ -0,0 +1,7 @@
+package main
+
+import "github.com/topolvm/topolvm/cmd/topolvm-controller/app"
+
+func main() {
+	app.Execute()
+}
diff --git a/pkg/topolvm-node/cmd/root.go b/cmd/topolvm-node/app/root.go
similarity index 97%
rename from pkg/topolvm-node/cmd/root.go
rename to cmd/topolvm-node/app/root.go
index 0b7a55ee..cc64661d 100644
--- a/pkg/topolvm-node/cmd/root.go
+++ b/cmd/topolvm-node/app/root.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"flag"
@@ -9,7 +9,7 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 	"github.com/topolvm/topolvm"
-	lvmd "github.com/topolvm/topolvm/pkg/lvmd/cmd"
+	lvmd "github.com/topolvm/topolvm/cmd/lvmd/app"
 	"k8s.io/klog/v2"
 	"sigs.k8s.io/controller-runtime/pkg/log/zap"
 )
diff --git a/pkg/topolvm-node/cmd/run.go b/cmd/topolvm-node/app/run.go
similarity index 91%
rename from pkg/topolvm-node/cmd/run.go
rename to cmd/topolvm-node/app/run.go
index e3d34238..e8854e36 100644
--- a/pkg/topolvm-node/cmd/run.go
+++ b/cmd/topolvm-node/app/run.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"context"
@@ -15,13 +15,13 @@ import (
 	"github.com/topolvm/topolvm"
 	topolvmlegacyv1 "github.com/topolvm/topolvm/api/legacy/v1"
 	topolvmv1 "github.com/topolvm/topolvm/api/v1"
-	clientwrapper "github.com/topolvm/topolvm/client"
-	"github.com/topolvm/topolvm/controllers"
-	"github.com/topolvm/topolvm/driver"
-	"github.com/topolvm/topolvm/lvmd"
-	"github.com/topolvm/topolvm/lvmd/command"
-	"github.com/topolvm/topolvm/lvmd/proto"
-	"github.com/topolvm/topolvm/runners"
+	clientwrapper "github.com/topolvm/topolvm/internal/client"
+	"github.com/topolvm/topolvm/internal/controller"
+	"github.com/topolvm/topolvm/internal/driver"
+	"github.com/topolvm/topolvm/internal/lvmd"
+	"github.com/topolvm/topolvm/internal/lvmd/command"
+	"github.com/topolvm/topolvm/internal/runners"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials/insecure"
 	"google.golang.org/grpc/health/grpc_health_v1"
@@ -103,7 +103,7 @@ func subMain(ctx context.Context) error {
 		health = grpc_health_v1.NewHealthClient(conn)
 	}
 
-	lvcontroller := controllers.NewLogicalVolumeReconcilerWithServices(client, nodename, vgService, lvService)
+	lvcontroller := controller.NewLogicalVolumeReconcilerWithServices(client, nodename, vgService, lvService)
 
 	if err := lvcontroller.SetupWithManager(mgr); err != nil {
 		setupLog.Error(err, "unable to create controller", "controller", "LogicalVolume")
@@ -125,7 +125,7 @@ func subMain(ctx context.Context) error {
 	}
 
 	// Add gRPC server to manager.
-	if err := os.MkdirAll(driver.DeviceDirectory, 0755); err != nil {
+	if err := os.MkdirAll(topolvm.DeviceDirectory, 0755); err != nil {
 		return err
 	}
 	grpcServer := grpc.NewServer(grpc.UnaryInterceptor(ErrorLoggingInterceptor))
diff --git a/pkg/topolvm-node/main.go b/cmd/topolvm-node/main.go
similarity index 57%
rename from pkg/topolvm-node/main.go
rename to cmd/topolvm-node/main.go
index 7aefb43d..0f145ae9 100644
--- a/pkg/topolvm-node/main.go
+++ b/cmd/topolvm-node/main.go
@@ -1,10 +1,10 @@
 package main
 
 import (
-	"github.com/topolvm/topolvm/pkg/topolvm-node/cmd"
+	"github.com/topolvm/topolvm/cmd/topolvm-node/app"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
 )
 
 func main() {
-	cmd.Execute()
+	app.Execute()
 }
diff --git a/pkg/topolvm-scheduler/cmd/access_log.go b/cmd/topolvm-scheduler/app/access_log.go
similarity index 99%
rename from pkg/topolvm-scheduler/cmd/access_log.go
rename to cmd/topolvm-scheduler/app/access_log.go
index e1902e75..5f1cd6b7 100644
--- a/pkg/topolvm-scheduler/cmd/access_log.go
+++ b/cmd/topolvm-scheduler/app/access_log.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"context"
diff --git a/pkg/topolvm-scheduler/cmd/root.go b/cmd/topolvm-scheduler/app/root.go
similarity index 98%
rename from pkg/topolvm-scheduler/cmd/root.go
rename to cmd/topolvm-scheduler/app/root.go
index d31ee1b1..8e04bb86 100644
--- a/pkg/topolvm-scheduler/cmd/root.go
+++ b/cmd/topolvm-scheduler/app/root.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"context"
@@ -13,7 +13,7 @@ import (
 
 	"github.com/spf13/cobra"
 	"github.com/topolvm/topolvm"
-	"github.com/topolvm/topolvm/scheduler"
+	"github.com/topolvm/topolvm/internal/scheduler"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 	"sigs.k8s.io/controller-runtime/pkg/log/zap"
diff --git a/cmd/topolvm-scheduler/main.go b/cmd/topolvm-scheduler/main.go
new file mode 100644
index 00000000..26599962
--- /dev/null
+++ b/cmd/topolvm-scheduler/main.go
@@ -0,0 +1,7 @@
+package main
+
+import "github.com/topolvm/topolvm/cmd/topolvm-scheduler/app"
+
+func main() {
+	app.Execute()
+}
diff --git a/constants.go b/constants.go
index 29252513..59afd8ce 100644
--- a/constants.go
+++ b/constants.go
@@ -100,3 +100,6 @@ const CreatedbyLabelKey = "app.kubernetes.io/created-by"
 
 // Label value that indicates The controller/user who created this resource
 const CreatedbyLabelValue = "topolvm-controller"
+
+// DeviceDirectory is a directory where TopoLVM Node service creates device files.
+const DeviceDirectory = "/dev/topolvm"
diff --git a/docs/lvmd-protocol.md b/docs/lvmd-protocol.md
index ce0c430a..a61395a5 100644
--- a/docs/lvmd-protocol.md
+++ b/docs/lvmd-protocol.md
@@ -3,7 +3,7 @@
 
 ## Table of Contents
 
-- [lvmd/proto/lvmd.proto](#lvmd/proto/lvmd.proto)
+- [pkg/lvmd/proto/lvmd.proto](#pkg/lvmd/proto/lvmd.proto)
     - [CreateLVRequest](#proto.CreateLVRequest)
     - [CreateLVResponse](#proto.CreateLVResponse)
     - [CreateLVSnapshotRequest](#proto.CreateLVSnapshotRequest)
@@ -27,10 +27,10 @@
 
 
 
-<a name="lvmd/proto/lvmd.proto"></a>
+<a name="pkg/lvmd/proto/lvmd.proto"></a>
 <p align="right"><a href="#top">Top</a></p>
 
-## lvmd/proto/lvmd.proto
+## pkg/lvmd/proto/lvmd.proto
 LVMd manages logical volumes of an LVM volume group.
 
 The protocol consists of two services:
diff --git a/example/Makefile b/example/Makefile
index a09987ee..e29a366f 100644
--- a/example/Makefile
+++ b/example/Makefile
@@ -10,7 +10,7 @@ HELM := $(BINDIR)/helm
 KUBECTL := $(BINDIR)/kubectl
 KIND := ../bin/kind
 
-GO_FILES := $(shell find .. -prune -o -path ../e2e -prune -o -name '*.go' -print)
+GO_FILES := $(shell find .. -prune -o -path ../test/e2e -prune -o -name '*.go' -print)
 BACKING_STORE := ./build
 
 BUILD_IMAGE := false
@@ -92,7 +92,7 @@ shutdown-kind:
 
 .PHONY: start-lvmd
 start-lvmd: $(TMPDIR)/lvmd/lvmd.yaml
-	go build -o build/lvmd ../pkg/lvmd
+	go build -o build/lvmd ../cmd/lvmd
 	if [ -f $(BACKING_STORE)/backing_store ]; then $(MAKE) stop-lvmd; fi; \
 	mkdir -p $(TMPDIR)/worker; \
 	mkdir -p $(TMPDIR)/lvmd; \
diff --git a/controllers/constants.go b/internal/controller/constants.go
similarity index 96%
rename from controllers/constants.go
rename to internal/controller/constants.go
index c6c72108..aa626fd6 100644
--- a/controllers/constants.go
+++ b/internal/controller/constants.go
@@ -1,4 +1,4 @@
-package controllers
+package controller
 
 const (
 	// keySelectedNode is a PVC resource indexing key for the controller
diff --git a/controllers/logicalvolume_controller.go b/internal/controller/logicalvolume_controller.go
similarity index 99%
rename from controllers/logicalvolume_controller.go
rename to internal/controller/logicalvolume_controller.go
index 54c3c64d..7979f0cd 100644
--- a/controllers/logicalvolume_controller.go
+++ b/internal/controller/logicalvolume_controller.go
@@ -1,4 +1,4 @@
-package controllers
+package controller
 
 import (
 	"context"
@@ -8,7 +8,7 @@ import (
 	"github.com/topolvm/topolvm"
 	topolvmlegacyv1 "github.com/topolvm/topolvm/api/legacy/v1"
 	topolvmv1 "github.com/topolvm/topolvm/api/v1"
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	apierrs "k8s.io/apimachinery/pkg/api/errors"
diff --git a/controllers/node_controller.go b/internal/controller/node_controller.go
similarity index 99%
rename from controllers/node_controller.go
rename to internal/controller/node_controller.go
index c50acd03..7398906d 100644
--- a/controllers/node_controller.go
+++ b/internal/controller/node_controller.go
@@ -1,4 +1,4 @@
-package controllers
+package controller
 
 import (
 	"context"
diff --git a/controllers/persistentvolumeclaim_controller.go b/internal/controller/persistentvolumeclaim_controller.go
similarity index 98%
rename from controllers/persistentvolumeclaim_controller.go
rename to internal/controller/persistentvolumeclaim_controller.go
index b12510a9..c29a1209 100644
--- a/controllers/persistentvolumeclaim_controller.go
+++ b/internal/controller/persistentvolumeclaim_controller.go
@@ -1,4 +1,4 @@
-package controllers
+package controller
 
 import (
 	"context"
@@ -21,7 +21,7 @@ type PersistentVolumeClaimReconciler struct {
 	apiReader client.Reader
 }
 
-// NewPersistentVolumeClaimReconciler returns NodeReconciler.
+// NewPersistentVolumeClaimReconciler returns PersistentVolumeClaimReconciler.
 func NewPersistentVolumeClaimReconciler(client client.Client, apiReader client.Reader) *PersistentVolumeClaimReconciler {
 	return &PersistentVolumeClaimReconciler{
 		client:    client,
diff --git a/driver/controller.go b/internal/driver/controller.go
similarity index 99%
rename from driver/controller.go
rename to internal/driver/controller.go
index 21e9e60e..7340d882 100644
--- a/driver/controller.go
+++ b/internal/driver/controller.go
@@ -11,7 +11,7 @@ import (
 	"github.com/golang/protobuf/ptypes/timestamp"
 	"github.com/topolvm/topolvm"
 	v1 "github.com/topolvm/topolvm/api/v1"
-	"github.com/topolvm/topolvm/driver/internal/k8s"
+	"github.com/topolvm/topolvm/internal/driver/internal/k8s"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	ctrl "sigs.k8s.io/controller-runtime"
diff --git a/driver/controller_test.go b/internal/driver/controller_test.go
similarity index 100%
rename from driver/controller_test.go
rename to internal/driver/controller_test.go
diff --git a/driver/identity.go b/internal/driver/identity.go
similarity index 100%
rename from driver/identity.go
rename to internal/driver/identity.go
diff --git a/driver/internal/k8s/logicalvolume_service.go b/internal/driver/internal/k8s/logicalvolume_service.go
similarity index 99%
rename from driver/internal/k8s/logicalvolume_service.go
rename to internal/driver/internal/k8s/logicalvolume_service.go
index 11abe1f6..9abce199 100644
--- a/driver/internal/k8s/logicalvolume_service.go
+++ b/internal/driver/internal/k8s/logicalvolume_service.go
@@ -9,8 +9,8 @@ import (
 	"github.com/topolvm/topolvm"
 	topolvmlegacyv1 "github.com/topolvm/topolvm/api/legacy/v1"
 	topolvmv1 "github.com/topolvm/topolvm/api/v1"
-	clientwrapper "github.com/topolvm/topolvm/client"
-	"github.com/topolvm/topolvm/getter"
+	clientwrapper "github.com/topolvm/topolvm/internal/client"
+	"github.com/topolvm/topolvm/internal/getter"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/driver/internal/k8s/node_service.go b/internal/driver/internal/k8s/node_service.go
similarity index 100%
rename from driver/internal/k8s/node_service.go
rename to internal/driver/internal/k8s/node_service.go
diff --git a/driver/lock.go b/internal/driver/lock.go
similarity index 100%
rename from driver/lock.go
rename to internal/driver/lock.go
diff --git a/driver/lock_test.go b/internal/driver/lock_test.go
similarity index 100%
rename from driver/lock_test.go
rename to internal/driver/lock_test.go
diff --git a/driver/node.go b/internal/driver/node.go
similarity index 97%
rename from driver/node.go
rename to internal/driver/node.go
index ff5316e1..0d67b651 100644
--- a/driver/node.go
+++ b/internal/driver/node.go
@@ -11,9 +11,9 @@ import (
 
 	"github.com/container-storage-interface/spec/lib/go/csi"
 	"github.com/topolvm/topolvm"
-	"github.com/topolvm/topolvm/driver/internal/k8s"
-	"github.com/topolvm/topolvm/filesystem"
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/internal/driver/internal/k8s"
+	"github.com/topolvm/topolvm/internal/filesystem"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
 	"golang.org/x/sys/unix"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
@@ -24,9 +24,6 @@ import (
 )
 
 const (
-	// DeviceDirectory is a directory where TopoLVM Node service creates device files.
-	DeviceDirectory = "/dev/topolvm"
-
 	findmntCmd = "/bin/findmnt"
 
 	deviceMode = 0600 | unix.S_IFBLK
@@ -208,7 +205,7 @@ func (s *nodeServerNoLocked) nodePublishFilesystemVolume(req *csi.NodePublishVol
 	}
 
 	// Find lv and create a block device with it
-	device := filepath.Join(DeviceDirectory, req.GetVolumeId())
+	device := filepath.Join(topolvm.DeviceDirectory, req.GetVolumeId())
 	err := s.createDeviceIfNeeded(device, lv)
 	if err != nil {
 		return err
@@ -340,7 +337,7 @@ func (s *nodeServerNoLocked) NodeUnpublishVolume(ctx context.Context, req *csi.N
 		return nil, status.Error(codes.InvalidArgument, "no target_path is provided")
 	}
 
-	device := filepath.Join(DeviceDirectory, volumeID)
+	device := filepath.Join(topolvm.DeviceDirectory, volumeID)
 
 	info, err := os.Stat(targetPath)
 	if os.IsNotExist(err) {
@@ -509,7 +506,7 @@ func (s *nodeServerNoLocked) NodeExpandVolume(ctx context.Context, req *csi.Node
 		return &csi.NodeExpandVolumeResponse{}, nil
 	}
 
-	device := filepath.Join(DeviceDirectory, volumeID)
+	device := filepath.Join(topolvm.DeviceDirectory, volumeID)
 	lvr, err := s.k8sLVService.GetVolume(ctx, volumeID)
 	deviceClass := topolvm.DefaultDeviceClassName
 	if err == nil {
diff --git a/driver/node_test.go b/internal/driver/node_test.go
similarity index 100%
rename from driver/node_test.go
rename to internal/driver/node_test.go
diff --git a/filesystem/util.go b/internal/filesystem/util.go
similarity index 100%
rename from filesystem/util.go
rename to internal/filesystem/util.go
diff --git a/filesystem/util_test.go b/internal/filesystem/util_test.go
similarity index 100%
rename from filesystem/util_test.go
rename to internal/filesystem/util_test.go
diff --git a/getter/getter.go b/internal/getter/getter.go
similarity index 100%
rename from getter/getter.go
rename to internal/getter/getter.go
diff --git a/getter/interface.go b/internal/getter/interface.go
similarity index 100%
rename from getter/interface.go
rename to internal/getter/interface.go
diff --git a/hook/mutate_persistentvolumeclaim.go b/internal/hook/mutate_persistentvolumeclaim.go
similarity index 98%
rename from hook/mutate_persistentvolumeclaim.go
rename to internal/hook/mutate_persistentvolumeclaim.go
index ada107ee..bc082c39 100644
--- a/hook/mutate_persistentvolumeclaim.go
+++ b/internal/hook/mutate_persistentvolumeclaim.go
@@ -6,7 +6,7 @@ import (
 	"net/http"
 
 	"github.com/topolvm/topolvm"
-	"github.com/topolvm/topolvm/getter"
+	"github.com/topolvm/topolvm/internal/getter"
 	corev1 "k8s.io/api/core/v1"
 	storagev1 "k8s.io/api/storage/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/hook/mutate_persistentvolumeclaim_test.go b/internal/hook/mutate_persistentvolumeclaim_test.go
similarity index 100%
rename from hook/mutate_persistentvolumeclaim_test.go
rename to internal/hook/mutate_persistentvolumeclaim_test.go
diff --git a/hook/mutate_pod.go b/internal/hook/mutate_pod.go
similarity index 99%
rename from hook/mutate_pod.go
rename to internal/hook/mutate_pod.go
index ffc9550d..adf244d0 100644
--- a/hook/mutate_pod.go
+++ b/internal/hook/mutate_pod.go
@@ -7,7 +7,7 @@ import (
 	"strconv"
 
 	"github.com/topolvm/topolvm"
-	"github.com/topolvm/topolvm/getter"
+	"github.com/topolvm/topolvm/internal/getter"
 	corev1 "k8s.io/api/core/v1"
 	storagev1 "k8s.io/api/storage/v1"
 	apierrs "k8s.io/apimachinery/pkg/api/errors"
diff --git a/lvmd/command/lvm_vgs.go b/internal/lvmd/command/lvm_vgs.go
similarity index 100%
rename from lvmd/command/lvm_vgs.go
rename to internal/lvmd/command/lvm_vgs.go
diff --git a/lvmd/device_class_manager.go b/internal/lvmd/device_class_manager.go
similarity index 64%
rename from lvmd/device_class_manager.go
rename to internal/lvmd/device_class_manager.go
index f551679e..57dfb9c5 100644
--- a/lvmd/device_class_manager.go
+++ b/internal/lvmd/device_class_manager.go
@@ -6,17 +6,14 @@ import (
 	"regexp"
 
 	"github.com/topolvm/topolvm"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 )
 
 // ErrNotFound is returned when a VG or LV is not found.
 var ErrNotFound = errors.New("device-class not found")
 
-type DeviceType string
-
 const (
 	defaultSpareGB = 10
-	TypeThin       = DeviceType("thin")
-	TypeThick      = DeviceType("thick")
 )
 
 // This regexp is based on the following validation:
@@ -27,47 +24,16 @@ var qualifiedNameRegexp = regexp.MustCompile("^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Z
 // This regexp is used to check StripeSize format
 var stripeSizeRegexp = regexp.MustCompile("(?i)^([0-9]*)(k|m|g|t|p|e|b|s)?$")
 
-// ThinPoolConfig holds the configuration of thin pool in a volume group
-type ThinPoolConfig struct {
-	// Name of thinpool
-	Name string `json:"name"`
-	// OverprovisionRatio signifies the upper bound multiplier for allowing logical volume creation in this pool
-	OverprovisionRatio float64 `json:"overprovision-ratio"`
-}
-
-// DeviceClass maps between device-classes and target for logical volume creation
-// current targets are VolumeGroup for thick-lv and ThinPool for thin-lv
-type DeviceClass struct {
-	// Name for the device-class name
-	Name string `json:"name"`
-	// Volume group name for the device-class
-	VolumeGroup string `json:"volume-group"`
-	// Default is a flag to indicate whether the device-class is the default
-	Default bool `json:"default"`
-	// SpareGB is storage capacity in GiB to be spared
-	SpareGB *uint64 `json:"spare-gb"`
-	// Stripe is the number of stripes in the logical volume
-	Stripe *uint `json:"stripe"`
-	// StripeSize is the amount of data that is written to one device before moving to the next device
-	StripeSize string `json:"stripe-size"`
-	// LVCreateOptions are extra arguments to pass to lvcreate
-	LVCreateOptions []string `json:"lvcreate-options"`
-	// Type is the name of logical volume target, supports 'thick' (default) or 'thin' currently
-	Type DeviceType `json:"type"`
-	// ThinPoolConfig holds the configuration for thinpool in this volume group corresponding to the device-class
-	ThinPoolConfig *ThinPoolConfig `json:"thin-pool"`
-}
-
 // GetSpare returns spare in bytes for the device-class
-func (c DeviceClass) GetSpare() uint64 {
-	if c.SpareGB == nil {
+func GetSpare(dc *lvmdTypes.DeviceClass) uint64 {
+	if dc.SpareGB == nil {
 		return defaultSpareGB << 30
 	}
-	return *c.SpareGB << 30
+	return *dc.SpareGB << 30
 }
 
 // ValidateDeviceClasses validates device-classes
-func ValidateDeviceClasses(deviceClasses []*DeviceClass) error {
+func ValidateDeviceClasses(deviceClasses []*lvmdTypes.DeviceClass) error {
 	if len(deviceClasses) < 1 {
 		return errors.New("should have at least one device-class")
 	}
@@ -95,15 +61,15 @@ func ValidateDeviceClasses(deviceClasses []*DeviceClass) error {
 
 		// validate Type of the device-class
 		switch dc.Type {
-		case "", TypeThick, TypeThin:
+		case "", lvmdTypes.TypeThick, lvmdTypes.TypeThin:
 		default:
-			return fmt.Errorf("target 'type' of device-class can be one of '%[1]s' or '%[2]s' or empty to default to '%[1]s'", TypeThick, TypeThin)
+			return fmt.Errorf("target 'type' of device-class can be one of '%[1]s' or '%[2]s' or empty to default to '%[1]s'", lvmdTypes.TypeThick, lvmdTypes.TypeThin)
 		}
 
 		name := dc.VolumeGroup
 
 		// thinpool validation, ignore any thinpoolconfig if Type is not TypeThin
-		if dc.Type == TypeThin {
+		if dc.Type == lvmdTypes.TypeThin {
 
 			if dc.ThinPoolConfig == nil {
 				return fmt.Errorf("device class type is thin but thinpool config is empty: %s", dc.Name)
@@ -139,18 +105,18 @@ func ValidateDeviceClasses(deviceClasses []*DeviceClass) error {
 
 // DeviceClassManager maps between device-classes and volume groups.
 type DeviceClassManager struct {
-	defaultDeviceClass        *DeviceClass
-	deviceClassByName         map[string]*DeviceClass
-	deviceClassByVGName       map[string]*DeviceClass
-	deviceClassByThinPoolName map[string]*DeviceClass
+	defaultDeviceClass        *lvmdTypes.DeviceClass
+	deviceClassByName         map[string]*lvmdTypes.DeviceClass
+	deviceClassByVGName       map[string]*lvmdTypes.DeviceClass
+	deviceClassByThinPoolName map[string]*lvmdTypes.DeviceClass
 }
 
 // NewDeviceClassManager creates a new DeviceClassManager
-func NewDeviceClassManager(deviceClasses []*DeviceClass) *DeviceClassManager {
+func NewDeviceClassManager(deviceClasses []*lvmdTypes.DeviceClass) *DeviceClassManager {
 	dcm := DeviceClassManager{}
-	dcm.deviceClassByName = make(map[string]*DeviceClass)
-	dcm.deviceClassByVGName = make(map[string]*DeviceClass)
-	dcm.deviceClassByThinPoolName = make(map[string]*DeviceClass)
+	dcm.deviceClassByName = make(map[string]*lvmdTypes.DeviceClass)
+	dcm.deviceClassByVGName = make(map[string]*lvmdTypes.DeviceClass)
+	dcm.deviceClassByThinPoolName = make(map[string]*lvmdTypes.DeviceClass)
 	for _, dc := range deviceClasses {
 		if dc.Default {
 			dcm.defaultDeviceClass = dc
@@ -160,12 +126,12 @@ func NewDeviceClassManager(deviceClasses []*DeviceClass) *DeviceClassManager {
 		// device-class has two targets and at a time it can only be in one of
 		// "deviceClassByVGName" or "deviceClassByThinPoolName" maps
 		switch dc.Type {
-		case "", TypeThick:
+		case "", lvmdTypes.TypeThick:
 			// device-class target is volumegroup and any logical volume referring to
 			// this device-class will have thick logical volumes
-			dc.Type = TypeThick
+			dc.Type = lvmdTypes.TypeThick
 			dcm.deviceClassByVGName[dc.VolumeGroup] = dc
-		case TypeThin:
+		case lvmdTypes.TypeThin:
 			// we can't store pool name alone as there can be of thinpool with same name
 			// but on a different vg, so combination of vg and thinpool should be unique
 			dcm.deviceClassByThinPoolName[dc.VolumeGroup+"/"+dc.ThinPoolConfig.Name] = dc
@@ -175,7 +141,7 @@ func NewDeviceClassManager(deviceClasses []*DeviceClass) *DeviceClassManager {
 }
 
 // DeviceClass returns the device-class by its name
-func (m DeviceClassManager) DeviceClass(dcName string) (*DeviceClass, error) {
+func (m DeviceClassManager) DeviceClass(dcName string) (*lvmdTypes.DeviceClass, error) {
 	if dcName == topolvm.DefaultDeviceClassName && m.defaultDeviceClass != nil {
 		return m.defaultDeviceClass, nil
 	}
@@ -186,7 +152,7 @@ func (m DeviceClassManager) DeviceClass(dcName string) (*DeviceClass, error) {
 }
 
 // FindDeviceClassByVGName returns the device-class with the volume group name
-func (m DeviceClassManager) FindDeviceClassByVGName(vgName string) (*DeviceClass, error) {
+func (m DeviceClassManager) FindDeviceClassByVGName(vgName string) (*lvmdTypes.DeviceClass, error) {
 	if v, ok := m.deviceClassByVGName[vgName]; ok {
 		return v, nil
 	}
@@ -194,7 +160,7 @@ func (m DeviceClassManager) FindDeviceClassByVGName(vgName string) (*DeviceClass
 }
 
 // FindDeviceClassByThinPoolName returns the device-class with volume group and pool combination
-func (m DeviceClassManager) FindDeviceClassByThinPoolName(vgName string, poolName string) (*DeviceClass, error) {
+func (m DeviceClassManager) FindDeviceClassByThinPoolName(vgName string, poolName string) (*lvmdTypes.DeviceClass, error) {
 	name := vgName + "/" + poolName
 	if v, ok := m.deviceClassByThinPoolName[name]; ok {
 		return v, nil
diff --git a/lvmd/embed.go b/internal/lvmd/embed.go
similarity index 99%
rename from lvmd/embed.go
rename to internal/lvmd/embed.go
index f1585801..4ceccff9 100644
--- a/lvmd/embed.go
+++ b/internal/lvmd/embed.go
@@ -4,7 +4,7 @@ import (
 	"context"
 	"time"
 
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/metadata"
diff --git a/lvmd/healthservice.go b/internal/lvmd/healthservice.go
similarity index 100%
rename from lvmd/healthservice.go
rename to internal/lvmd/healthservice.go
diff --git a/internal/lvmd/lvcreate_option_class_manager.go b/internal/lvmd/lvcreate_option_class_manager.go
new file mode 100644
index 00000000..3dab93c3
--- /dev/null
+++ b/internal/lvmd/lvcreate_option_class_manager.go
@@ -0,0 +1,24 @@
+package lvmd
+
+import (
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
+)
+
+type LvcreateOptionClassManager struct {
+	LvcreateOptionClassByName map[string]*lvmdTypes.LvcreateOptionClass
+}
+
+// NewLvcreateOptionClassManager creates a new LvcreateOptionClassManager
+func NewLvcreateOptionClassManager(LvcreateOptionClasses []*lvmdTypes.LvcreateOptionClass) *LvcreateOptionClassManager {
+	cm := LvcreateOptionClassManager{}
+	cm.LvcreateOptionClassByName = make(map[string]*lvmdTypes.LvcreateOptionClass)
+	for _, c := range LvcreateOptionClasses {
+		cm.LvcreateOptionClassByName[c.Name] = c
+	}
+	return &cm
+}
+
+// LvcreateOptionClassClass returns the lvcreate-option-class by its name
+func (m LvcreateOptionClassManager) LvcreateOptionClass(name string) *lvmdTypes.LvcreateOptionClass {
+	return m.LvcreateOptionClassByName[name]
+}
diff --git a/lvmd/lvservice.go b/internal/lvmd/lvservice.go
similarity index 97%
rename from lvmd/lvservice.go
rename to internal/lvmd/lvservice.go
index b960c0b8..93cc7c9f 100644
--- a/lvmd/lvservice.go
+++ b/internal/lvmd/lvservice.go
@@ -6,8 +6,9 @@ import (
 	"fmt"
 	"math"
 
-	"github.com/topolvm/topolvm/lvmd/command"
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/internal/lvmd/command"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"sigs.k8s.io/controller-runtime/pkg/log"
@@ -61,13 +62,13 @@ func (s *lvService) CreateLV(ctx context.Context, req *proto.CreateLVRequest) (*
 	free := uint64(0)
 	var pool *command.ThinPool
 	switch dc.Type {
-	case TypeThick:
+	case lvmdTypes.TypeThick:
 		free, err = vg.Free()
 		if err != nil {
 			logger.Error(err, "failed to get free bytes")
 			return nil, status.Error(codes.Internal, err.Error())
 		}
-	case TypeThin:
+	case lvmdTypes.TypeThin:
 		pool, err = vg.FindPool(ctx, dc.ThinPoolConfig.Name)
 		if err != nil {
 			logger.Error(err, "failed to get thinpool")
@@ -108,9 +109,9 @@ func (s *lvService) CreateLV(ctx context.Context, req *proto.CreateLVRequest) (*
 	}
 
 	switch dc.Type {
-	case TypeThick:
+	case lvmdTypes.TypeThick:
 		err = vg.CreateVolume(ctx, req.GetName(), requested, req.GetTags(), stripe, stripeSize, lvcreateOptions)
-	case TypeThin:
+	case lvmdTypes.TypeThin:
 		err = pool.CreateVolume(ctx, req.GetName(), requested, req.GetTags(), stripe, stripeSize, lvcreateOptions)
 	default:
 		return nil, status.Error(codes.Internal, fmt.Sprintf("unsupported device class target: %s", dc.Type))
@@ -189,9 +190,9 @@ func (s *lvService) CreateLVSnapshot(ctx context.Context, req *proto.CreateLVSna
 	}
 
 	switch dc.Type {
-	case TypeThin:
+	case lvmdTypes.TypeThin:
 		snapType = "thin-snapshot"
-	case TypeThick:
+	case lvmdTypes.TypeThick:
 		return nil, status.Error(codes.Unimplemented, "device class is not thin. Thick snapshots are not implemented yet")
 	default:
 		return nil, status.Errorf(codes.InvalidArgument, "invalid device class type %v", string(dc.Type))
@@ -346,13 +347,13 @@ func (s *lvService) ResizeLV(ctx context.Context, req *proto.ResizeLVRequest) (*
 	free := uint64(0)
 	var pool *command.ThinPool
 	switch dc.Type {
-	case TypeThick:
+	case lvmdTypes.TypeThick:
 		free, err = vg.Free()
 		if err != nil {
 			logger.Error(err, "failed to get free bytes")
 			return nil, status.Error(codes.Internal, err.Error())
 		}
-	case TypeThin:
+	case lvmdTypes.TypeThin:
 		pool, err = vg.FindPool(ctx, dc.ThinPoolConfig.Name)
 		if err != nil {
 			logger.Error(err, "failed to get thinpool")
diff --git a/lvmd/testutils/test_utils.go b/internal/lvmd/testutils/test_utils.go
similarity index 100%
rename from lvmd/testutils/test_utils.go
rename to internal/lvmd/testutils/test_utils.go
diff --git a/lvmd/vgservice.go b/internal/lvmd/vgservice.go
similarity index 94%
rename from lvmd/vgservice.go
rename to internal/lvmd/vgservice.go
index c6f5a144..2a5f6181 100644
--- a/lvmd/vgservice.go
+++ b/internal/lvmd/vgservice.go
@@ -7,8 +7,9 @@ import (
 	"math"
 	"sync"
 
-	"github.com/topolvm/topolvm/lvmd/command"
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/internal/lvmd/command"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"sigs.k8s.io/controller-runtime/pkg/log"
@@ -47,13 +48,13 @@ func (s *vgService) GetLVList(ctx context.Context, req *proto.GetLVListRequest)
 	var lvs map[string]*command.LogicalVolume
 
 	switch dc.Type {
-	case TypeThick:
+	case lvmdTypes.TypeThick:
 		// thick logicalvolumes
 		lvs, err = vg.ListVolumes(ctx)
 		if err != nil {
 			return nil, err
 		}
-	case TypeThin:
+	case lvmdTypes.TypeThin:
 		var pool *command.ThinPool
 		pool, err = vg.FindPool(ctx, dc.ThinPoolConfig.Name)
 		if err != nil {
@@ -72,7 +73,7 @@ func (s *vgService) GetLVList(ctx context.Context, req *proto.GetLVListRequest)
 
 	vols := make([]*proto.LogicalVolume, 0, len(lvs))
 	for _, lv := range lvs {
-		if dc.Type == TypeThick && lv.IsThin() {
+		if dc.Type == lvmdTypes.TypeThick && lv.IsThin() {
 			// do not send thin lvs if request is on TypeThick
 			continue
 		}
@@ -101,13 +102,13 @@ func (s *vgService) GetFreeBytes(ctx context.Context, req *proto.GetFreeBytesReq
 
 	var vgFree uint64
 	switch dc.Type {
-	case TypeThick:
+	case lvmdTypes.TypeThick:
 		vgFree, err = vg.Free()
 		if err != nil {
 			logger.Error(err, "failed to get free bytes")
 			return nil, status.Error(codes.Internal, err.Error())
 		}
-	case TypeThin:
+	case lvmdTypes.TypeThin:
 		pool, err := vg.FindPool(ctx, dc.ThinPoolConfig.Name)
 		if err != nil {
 			logger.Error(err, "failed to get thinpool")
@@ -126,7 +127,7 @@ func (s *vgService) GetFreeBytes(ctx context.Context, req *proto.GetFreeBytesReq
 		return nil, status.Error(codes.Internal, fmt.Sprintf("unsupported device class target: %s", dc.Type))
 	}
 
-	spare := dc.GetSpare()
+	spare := GetSpare(dc)
 	if vgFree < spare {
 		vgFree = 0
 	} else {
@@ -206,7 +207,7 @@ func (s *vgService) send(server proto.VGService_WatchServer) error {
 			continue
 		}
 
-		spare := dc.GetSpare()
+		spare := GetSpare(dc)
 		if vgFree < spare {
 			vgFree = 0
 		} else {
diff --git a/runners/checker.go b/internal/runners/checker.go
similarity index 100%
rename from runners/checker.go
rename to internal/runners/checker.go
diff --git a/runners/grpc.go b/internal/runners/grpc.go
similarity index 100%
rename from runners/grpc.go
rename to internal/runners/grpc.go
diff --git a/runners/metrics_exporter.go b/internal/runners/metrics_exporter.go
similarity index 99%
rename from runners/metrics_exporter.go
rename to internal/runners/metrics_exporter.go
index 46d238a7..4107abc9 100644
--- a/runners/metrics_exporter.go
+++ b/internal/runners/metrics_exporter.go
@@ -7,7 +7,7 @@ import (
 
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/topolvm/topolvm"
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	corev1 "k8s.io/api/core/v1"
diff --git a/scheduler/api.go b/internal/scheduler/api.go
similarity index 100%
rename from scheduler/api.go
rename to internal/scheduler/api.go
diff --git a/scheduler/predicate.go b/internal/scheduler/predicate.go
similarity index 100%
rename from scheduler/predicate.go
rename to internal/scheduler/predicate.go
diff --git a/scheduler/predicate_test.go b/internal/scheduler/predicate_test.go
similarity index 100%
rename from scheduler/predicate_test.go
rename to internal/scheduler/predicate_test.go
diff --git a/scheduler/prioritize.go b/internal/scheduler/prioritize.go
similarity index 100%
rename from scheduler/prioritize.go
rename to internal/scheduler/prioritize.go
diff --git a/scheduler/prioritize_test.go b/internal/scheduler/prioritize_test.go
similarity index 100%
rename from scheduler/prioritize_test.go
rename to internal/scheduler/prioritize_test.go
diff --git a/scheduler/route.go b/internal/scheduler/route.go
similarity index 100%
rename from scheduler/route.go
rename to internal/scheduler/route.go
diff --git a/scheduler/route_test.go b/internal/scheduler/route_test.go
similarity index 100%
rename from scheduler/route_test.go
rename to internal/scheduler/route_test.go
diff --git a/lvmd/lvcreate_option_class_manager.go b/lvmd/lvcreate_option_class_manager.go
deleted file mode 100644
index 3ec2d949..00000000
--- a/lvmd/lvcreate_option_class_manager.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package lvmd
-
-type LvcreateOptionClass struct {
-	// Name for the lvcreate-option-class name
-	Name string `json:"name"`
-	// Options are extra arguments to pass to lvcreate
-	Options []string `json:"options"`
-}
-
-type LvcreateOptionClassManager struct {
-	LvcreateOptionClassByName map[string]*LvcreateOptionClass
-}
-
-// NewLvcreateOptionClassManager creates a new LvcreateOptionClassManager
-func NewLvcreateOptionClassManager(LvcreateOptionClasses []*LvcreateOptionClass) *LvcreateOptionClassManager {
-	cm := LvcreateOptionClassManager{}
-	cm.LvcreateOptionClassByName = make(map[string]*LvcreateOptionClass)
-	for _, c := range LvcreateOptionClasses {
-		cm.LvcreateOptionClassByName[c.Name] = c
-	}
-	return &cm
-}
-
-// LvcreateOptionClassClass returns the lvcreate-option-class by its name
-func (m LvcreateOptionClassManager) LvcreateOptionClass(name string) *LvcreateOptionClass {
-	return m.LvcreateOptionClassByName[name]
-}
diff --git a/pkg/controller/logicalvolume_controller.go b/pkg/controller/logicalvolume_controller.go
new file mode 100644
index 00000000..49cae8fa
--- /dev/null
+++ b/pkg/controller/logicalvolume_controller.go
@@ -0,0 +1,14 @@
+package controller
+
+import (
+	internalController "github.com/topolvm/topolvm/internal/controller"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// SetupLogicalVolumeReconcilerWithServices creates LogicalVolumeReconciler and sets up with manager.
+func SetupLogicalVolumeReconcilerWithServices(mgr ctrl.Manager, client client.Client, nodeName string, vgService proto.VGServiceClient, lvService proto.LVServiceClient) error {
+	reconciler := internalController.NewLogicalVolumeReconcilerWithServices(client, nodeName, vgService, lvService)
+	return reconciler.SetupWithManager(mgr)
+}
diff --git a/pkg/controller/node_controller.go b/pkg/controller/node_controller.go
new file mode 100644
index 00000000..6d65e8bd
--- /dev/null
+++ b/pkg/controller/node_controller.go
@@ -0,0 +1,13 @@
+package controller
+
+import (
+	internalController "github.com/topolvm/topolvm/internal/controller"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// SetupNodeReconciler creates NodeReconciler and sets up with manager.
+func SetupNodeReconciler(mgr ctrl.Manager, client client.Client, skipNodeFinalize bool) error {
+	reconciler := internalController.NewNodeReconciler(client, skipNodeFinalize)
+	return reconciler.SetupWithManager(mgr)
+}
diff --git a/pkg/controller/persistentvolumeclaim_controller.go b/pkg/controller/persistentvolumeclaim_controller.go
new file mode 100644
index 00000000..85f28531
--- /dev/null
+++ b/pkg/controller/persistentvolumeclaim_controller.go
@@ -0,0 +1,13 @@
+package controller
+
+import (
+	internalController "github.com/topolvm/topolvm/internal/controller"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// SetupPersistentVolumeClaimReconciler creates PersistentVolumeClaimReconciler and sets up with manager.
+func SetupPersistentVolumeClaimReconciler(mgr ctrl.Manager, client client.Client, apiReader client.Reader) error {
+	reconciler := internalController.NewPersistentVolumeClaimReconciler(client, apiReader)
+	return reconciler.SetupWithManager(mgr)
+}
diff --git a/pkg/driver/controller.go b/pkg/driver/controller.go
new file mode 100644
index 00000000..c875e742
--- /dev/null
+++ b/pkg/driver/controller.go
@@ -0,0 +1,7 @@
+package driver
+
+import (
+	internalDriver "github.com/topolvm/topolvm/internal/driver"
+)
+
+var NewControllerServer = internalDriver.NewControllerServer
diff --git a/pkg/driver/identity.go b/pkg/driver/identity.go
new file mode 100644
index 00000000..f8123d89
--- /dev/null
+++ b/pkg/driver/identity.go
@@ -0,0 +1,7 @@
+package driver
+
+import (
+	internalDriver "github.com/topolvm/topolvm/internal/driver"
+)
+
+var NewIdentityServer = internalDriver.NewIdentityServer
diff --git a/pkg/driver/node.go b/pkg/driver/node.go
new file mode 100644
index 00000000..0819ec56
--- /dev/null
+++ b/pkg/driver/node.go
@@ -0,0 +1,7 @@
+package driver
+
+import (
+	internalDriver "github.com/topolvm/topolvm/internal/driver"
+)
+
+var NewNodeServer = internalDriver.NewNodeServer
diff --git a/pkg/lvmd/command.go b/pkg/lvmd/command.go
new file mode 100644
index 00000000..bbdb43b5
--- /dev/null
+++ b/pkg/lvmd/command.go
@@ -0,0 +1,9 @@
+package lvmd
+
+import (
+	internalLvmdCommand "github.com/topolvm/topolvm/internal/lvmd/command"
+)
+
+func Containerized(sw bool) {
+	internalLvmdCommand.Containerized = sw
+}
diff --git a/pkg/lvmd/embed.go b/pkg/lvmd/embed.go
new file mode 100644
index 00000000..83f9920e
--- /dev/null
+++ b/pkg/lvmd/embed.go
@@ -0,0 +1,19 @@
+package lvmd
+
+import (
+	"context"
+
+	internalLvmd "github.com/topolvm/topolvm/internal/lvmd"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
+)
+
+func NewEmbeddedServiceClients(ctx context.Context, deviceClasses []*lvmdTypes.DeviceClass, LvcreateOptionClasses []*lvmdTypes.LvcreateOptionClass) (
+	proto.LVServiceClient,
+	proto.VGServiceClient,
+) {
+	dcManager := internalLvmd.NewDeviceClassManager(deviceClasses)
+	lvOptionClassManager := internalLvmd.NewLvcreateOptionClassManager(LvcreateOptionClasses)
+
+	return internalLvmd.NewEmbeddedServiceClients(ctx, dcManager, lvOptionClassManager)
+}
diff --git a/pkg/lvmd/main.go b/pkg/lvmd/main.go
deleted file mode 100644
index 226556af..00000000
--- a/pkg/lvmd/main.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package main
-
-import "github.com/topolvm/topolvm/pkg/lvmd/cmd"
-
-func main() {
-	cmd.Execute()
-}
diff --git a/lvmd/proto/lvmd.pb.go b/pkg/lvmd/proto/lvmd.pb.go
similarity index 63%
rename from lvmd/proto/lvmd.pb.go
rename to pkg/lvmd/proto/lvmd.pb.go
index 602044f3..a9e8000d 100644
--- a/lvmd/proto/lvmd.pb.go
+++ b/pkg/lvmd/proto/lvmd.pb.go
@@ -8,8 +8,8 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
 // 	protoc-gen-go v1.31.0
-// 	protoc        v4.24.4
-// source: lvmd/proto/lvmd.proto
+// 	protoc        v4.25.2
+// source: pkg/lvmd/proto/lvmd.proto
 
 package proto
 
@@ -36,7 +36,7 @@ type Empty struct {
 func (x *Empty) Reset() {
 	*x = Empty{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[0]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[0]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -49,7 +49,7 @@ func (x *Empty) String() string {
 func (*Empty) ProtoMessage() {}
 
 func (x *Empty) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[0]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[0]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -62,7 +62,7 @@ func (x *Empty) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Empty.ProtoReflect.Descriptor instead.
 func (*Empty) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{0}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{0}
 }
 
 // Represents a logical volume.
@@ -72,7 +72,7 @@ type LogicalVolume struct {
 	unknownFields protoimpl.UnknownFields
 
 	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // The logical volume name.
-	// Deprecated: Marked as deprecated in lvmd/proto/lvmd.proto.
+	// Deprecated: Marked as deprecated in pkg/lvmd/proto/lvmd.proto.
 	SizeGb    uint64   `protobuf:"varint,2,opt,name=size_gb,json=sizeGb,proto3" json:"size_gb,omitempty"`          // Volume size in GiB.
 	DevMajor  uint32   `protobuf:"varint,3,opt,name=dev_major,json=devMajor,proto3" json:"dev_major,omitempty"`    // Device major number.
 	DevMinor  uint32   `protobuf:"varint,4,opt,name=dev_minor,json=devMinor,proto3" json:"dev_minor,omitempty"`    // Device minor number.
@@ -83,7 +83,7 @@ type LogicalVolume struct {
 func (x *LogicalVolume) Reset() {
 	*x = LogicalVolume{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[1]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[1]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -96,7 +96,7 @@ func (x *LogicalVolume) String() string {
 func (*LogicalVolume) ProtoMessage() {}
 
 func (x *LogicalVolume) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[1]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[1]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -109,7 +109,7 @@ func (x *LogicalVolume) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LogicalVolume.ProtoReflect.Descriptor instead.
 func (*LogicalVolume) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{1}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{1}
 }
 
 func (x *LogicalVolume) GetName() string {
@@ -119,7 +119,7 @@ func (x *LogicalVolume) GetName() string {
 	return ""
 }
 
-// Deprecated: Marked as deprecated in lvmd/proto/lvmd.proto.
+// Deprecated: Marked as deprecated in pkg/lvmd/proto/lvmd.proto.
 func (x *LogicalVolume) GetSizeGb() uint64 {
 	if x != nil {
 		return x.SizeGb
@@ -162,7 +162,7 @@ type CreateLVRequest struct {
 	unknownFields protoimpl.UnknownFields
 
 	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // The logical volume name.
-	// Deprecated: Marked as deprecated in lvmd/proto/lvmd.proto.
+	// Deprecated: Marked as deprecated in pkg/lvmd/proto/lvmd.proto.
 	SizeGb              uint64   `protobuf:"varint,2,opt,name=size_gb,json=sizeGb,proto3" json:"size_gb,omitempty"` // Volume size in GiB.
 	Tags                []string `protobuf:"bytes,3,rep,name=tags,proto3" json:"tags,omitempty"`                    // Tags to add to the volume during creation
 	DeviceClass         string   `protobuf:"bytes,4,opt,name=device_class,json=deviceClass,proto3" json:"device_class,omitempty"`
@@ -173,7 +173,7 @@ type CreateLVRequest struct {
 func (x *CreateLVRequest) Reset() {
 	*x = CreateLVRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[2]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[2]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -186,7 +186,7 @@ func (x *CreateLVRequest) String() string {
 func (*CreateLVRequest) ProtoMessage() {}
 
 func (x *CreateLVRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[2]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[2]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -199,7 +199,7 @@ func (x *CreateLVRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreateLVRequest.ProtoReflect.Descriptor instead.
 func (*CreateLVRequest) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{2}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{2}
 }
 
 func (x *CreateLVRequest) GetName() string {
@@ -209,7 +209,7 @@ func (x *CreateLVRequest) GetName() string {
 	return ""
 }
 
-// Deprecated: Marked as deprecated in lvmd/proto/lvmd.proto.
+// Deprecated: Marked as deprecated in pkg/lvmd/proto/lvmd.proto.
 func (x *CreateLVRequest) GetSizeGb() uint64 {
 	if x != nil {
 		return x.SizeGb
@@ -257,7 +257,7 @@ type CreateLVResponse struct {
 func (x *CreateLVResponse) Reset() {
 	*x = CreateLVResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[3]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[3]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -270,7 +270,7 @@ func (x *CreateLVResponse) String() string {
 func (*CreateLVResponse) ProtoMessage() {}
 
 func (x *CreateLVResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[3]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[3]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -283,7 +283,7 @@ func (x *CreateLVResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreateLVResponse.ProtoReflect.Descriptor instead.
 func (*CreateLVResponse) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{3}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *CreateLVResponse) GetVolume() *LogicalVolume {
@@ -306,7 +306,7 @@ type RemoveLVRequest struct {
 func (x *RemoveLVRequest) Reset() {
 	*x = RemoveLVRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[4]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[4]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -319,7 +319,7 @@ func (x *RemoveLVRequest) String() string {
 func (*RemoveLVRequest) ProtoMessage() {}
 
 func (x *RemoveLVRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[4]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[4]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -332,7 +332,7 @@ func (x *RemoveLVRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RemoveLVRequest.ProtoReflect.Descriptor instead.
 func (*RemoveLVRequest) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{4}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *RemoveLVRequest) GetName() string {
@@ -358,7 +358,7 @@ type CreateLVSnapshotRequest struct {
 	Tags         []string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty"` // Tags to add to the volume during creation
 	DeviceClass  string   `protobuf:"bytes,3,opt,name=device_class,json=deviceClass,proto3" json:"device_class,omitempty"`
 	SourceVolume string   `protobuf:"bytes,4,opt,name=source_volume,json=sourceVolume,proto3" json:"source_volume,omitempty"` // Source lv of snapshot.
-	// Deprecated: Marked as deprecated in lvmd/proto/lvmd.proto.
+	// Deprecated: Marked as deprecated in pkg/lvmd/proto/lvmd.proto.
 	SizeGb     uint64 `protobuf:"varint,5,opt,name=size_gb,json=sizeGb,proto3" json:"size_gb,omitempty"`            // Volume size in GiB.
 	AccessType string `protobuf:"bytes,6,opt,name=access_type,json=accessType,proto3" json:"access_type,omitempty"` // Access type of snapshot
 	SizeBytes  int64  `protobuf:"varint,7,opt,name=size_bytes,json=sizeBytes,proto3" json:"size_bytes,omitempty"`   // Volume size in canonical CSI bytes.
@@ -367,7 +367,7 @@ type CreateLVSnapshotRequest struct {
 func (x *CreateLVSnapshotRequest) Reset() {
 	*x = CreateLVSnapshotRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[5]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[5]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -380,7 +380,7 @@ func (x *CreateLVSnapshotRequest) String() string {
 func (*CreateLVSnapshotRequest) ProtoMessage() {}
 
 func (x *CreateLVSnapshotRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[5]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[5]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -393,7 +393,7 @@ func (x *CreateLVSnapshotRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreateLVSnapshotRequest.ProtoReflect.Descriptor instead.
 func (*CreateLVSnapshotRequest) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{5}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *CreateLVSnapshotRequest) GetName() string {
@@ -424,7 +424,7 @@ func (x *CreateLVSnapshotRequest) GetSourceVolume() string {
 	return ""
 }
 
-// Deprecated: Marked as deprecated in lvmd/proto/lvmd.proto.
+// Deprecated: Marked as deprecated in pkg/lvmd/proto/lvmd.proto.
 func (x *CreateLVSnapshotRequest) GetSizeGb() uint64 {
 	if x != nil {
 		return x.SizeGb
@@ -457,7 +457,7 @@ type CreateLVSnapshotResponse struct {
 func (x *CreateLVSnapshotResponse) Reset() {
 	*x = CreateLVSnapshotResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[6]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[6]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -470,7 +470,7 @@ func (x *CreateLVSnapshotResponse) String() string {
 func (*CreateLVSnapshotResponse) ProtoMessage() {}
 
 func (x *CreateLVSnapshotResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[6]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[6]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -483,7 +483,7 @@ func (x *CreateLVSnapshotResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CreateLVSnapshotResponse.ProtoReflect.Descriptor instead.
 func (*CreateLVSnapshotResponse) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{6}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *CreateLVSnapshotResponse) GetSnapshot() *LogicalVolume {
@@ -503,7 +503,7 @@ type ResizeLVRequest struct {
 	unknownFields protoimpl.UnknownFields
 
 	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // The logical volume name.
-	// Deprecated: Marked as deprecated in lvmd/proto/lvmd.proto.
+	// Deprecated: Marked as deprecated in pkg/lvmd/proto/lvmd.proto.
 	SizeGb      uint64 `protobuf:"varint,2,opt,name=size_gb,json=sizeGb,proto3" json:"size_gb,omitempty"`          // Volume size in GiB.
 	SizeBytes   int64  `protobuf:"varint,7,opt,name=size_bytes,json=sizeBytes,proto3" json:"size_bytes,omitempty"` // Volume size in canonical CSI bytes.
 	DeviceClass string `protobuf:"bytes,3,opt,name=device_class,json=deviceClass,proto3" json:"device_class,omitempty"`
@@ -512,7 +512,7 @@ type ResizeLVRequest struct {
 func (x *ResizeLVRequest) Reset() {
 	*x = ResizeLVRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[7]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[7]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -525,7 +525,7 @@ func (x *ResizeLVRequest) String() string {
 func (*ResizeLVRequest) ProtoMessage() {}
 
 func (x *ResizeLVRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[7]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[7]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -538,7 +538,7 @@ func (x *ResizeLVRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ResizeLVRequest.ProtoReflect.Descriptor instead.
 func (*ResizeLVRequest) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{7}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *ResizeLVRequest) GetName() string {
@@ -548,7 +548,7 @@ func (x *ResizeLVRequest) GetName() string {
 	return ""
 }
 
-// Deprecated: Marked as deprecated in lvmd/proto/lvmd.proto.
+// Deprecated: Marked as deprecated in pkg/lvmd/proto/lvmd.proto.
 func (x *ResizeLVRequest) GetSizeGb() uint64 {
 	if x != nil {
 		return x.SizeGb
@@ -582,7 +582,7 @@ type GetLVListResponse struct {
 func (x *GetLVListResponse) Reset() {
 	*x = GetLVListResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[8]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[8]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -595,7 +595,7 @@ func (x *GetLVListResponse) String() string {
 func (*GetLVListResponse) ProtoMessage() {}
 
 func (x *GetLVListResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[8]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[8]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -608,7 +608,7 @@ func (x *GetLVListResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetLVListResponse.ProtoReflect.Descriptor instead.
 func (*GetLVListResponse) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{8}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *GetLVListResponse) GetVolumes() []*LogicalVolume {
@@ -630,7 +630,7 @@ type GetFreeBytesResponse struct {
 func (x *GetFreeBytesResponse) Reset() {
 	*x = GetFreeBytesResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[9]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[9]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -643,7 +643,7 @@ func (x *GetFreeBytesResponse) String() string {
 func (*GetFreeBytesResponse) ProtoMessage() {}
 
 func (x *GetFreeBytesResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[9]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[9]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -656,7 +656,7 @@ func (x *GetFreeBytesResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetFreeBytesResponse.ProtoReflect.Descriptor instead.
 func (*GetFreeBytesResponse) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{9}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{9}
 }
 
 func (x *GetFreeBytesResponse) GetFreeBytes() uint64 {
@@ -677,7 +677,7 @@ type GetLVListRequest struct {
 func (x *GetLVListRequest) Reset() {
 	*x = GetLVListRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[10]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -690,7 +690,7 @@ func (x *GetLVListRequest) String() string {
 func (*GetLVListRequest) ProtoMessage() {}
 
 func (x *GetLVListRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[10]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -703,7 +703,7 @@ func (x *GetLVListRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetLVListRequest.ProtoReflect.Descriptor instead.
 func (*GetLVListRequest) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{10}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *GetLVListRequest) GetDeviceClass() string {
@@ -724,7 +724,7 @@ type GetFreeBytesRequest struct {
 func (x *GetFreeBytesRequest) Reset() {
 	*x = GetFreeBytesRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[11]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -737,7 +737,7 @@ func (x *GetFreeBytesRequest) String() string {
 func (*GetFreeBytesRequest) ProtoMessage() {}
 
 func (x *GetFreeBytesRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[11]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -750,7 +750,7 @@ func (x *GetFreeBytesRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use GetFreeBytesRequest.ProtoReflect.Descriptor instead.
 func (*GetFreeBytesRequest) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{11}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *GetFreeBytesRequest) GetDeviceClass() string {
@@ -773,7 +773,7 @@ type WatchResponse struct {
 func (x *WatchResponse) Reset() {
 	*x = WatchResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[12]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[12]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -786,7 +786,7 @@ func (x *WatchResponse) String() string {
 func (*WatchResponse) ProtoMessage() {}
 
 func (x *WatchResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[12]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[12]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -799,7 +799,7 @@ func (x *WatchResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use WatchResponse.ProtoReflect.Descriptor instead.
 func (*WatchResponse) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{12}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{12}
 }
 
 func (x *WatchResponse) GetFreeBytes() uint64 {
@@ -831,7 +831,7 @@ type ThinPoolItem struct {
 func (x *ThinPoolItem) Reset() {
 	*x = ThinPoolItem{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[13]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[13]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -844,7 +844,7 @@ func (x *ThinPoolItem) String() string {
 func (*ThinPoolItem) ProtoMessage() {}
 
 func (x *ThinPoolItem) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[13]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[13]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -857,7 +857,7 @@ func (x *ThinPoolItem) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ThinPoolItem.ProtoReflect.Descriptor instead.
 func (*ThinPoolItem) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{13}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *ThinPoolItem) GetDataPercent() float64 {
@@ -903,7 +903,7 @@ type WatchItem struct {
 func (x *WatchItem) Reset() {
 	*x = WatchItem{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_lvmd_proto_lvmd_proto_msgTypes[14]
+		mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[14]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -916,7 +916,7 @@ func (x *WatchItem) String() string {
 func (*WatchItem) ProtoMessage() {}
 
 func (x *WatchItem) ProtoReflect() protoreflect.Message {
-	mi := &file_lvmd_proto_lvmd_proto_msgTypes[14]
+	mi := &file_pkg_lvmd_proto_lvmd_proto_msgTypes[14]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -929,7 +929,7 @@ func (x *WatchItem) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use WatchItem.ProtoReflect.Descriptor instead.
 func (*WatchItem) Descriptor() ([]byte, []int) {
-	return file_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{14}
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *WatchItem) GetFreeBytes() uint64 {
@@ -960,161 +960,162 @@ func (x *WatchItem) GetThinPool() *ThinPoolItem {
 	return nil
 }
 
-var File_lvmd_proto_lvmd_proto protoreflect.FileDescriptor
-
-var file_lvmd_proto_lvmd_proto_rawDesc = []byte{
-	0x0a, 0x15, 0x6c, 0x76, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x76, 0x6d,
-	0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x07,
-	0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xad, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69,
-	0x63, 0x61, 0x6c, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
-	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a,
-	0x07, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02,
-	0x18, 0x01, 0x52, 0x06, 0x73, 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65,
-	0x76, 0x5f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64,
-	0x65, 0x76, 0x4d, 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x5f, 0x6d,
-	0x69, 0x6e, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x4d,
-	0x69, 0x6e, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03,
-	0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65,
-	0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x69,
-	0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0xcc, 0x01, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61,
-	0x74, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e,
-	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
-	0x1b, 0x0a, 0x07, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
-	0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x73, 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x12, 0x0a, 0x04,
-	0x74, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73,
-	0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c,
-	0x61, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6c, 0x76, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f,
-	0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x13, 0x6c, 0x76, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69,
-	0x6f, 0x6e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f,
-	0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x69, 0x7a,
-	0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x40, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
-	0x4c, 0x56, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x76, 0x6f,
-	0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65,
-	0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x22, 0x48, 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f,
-	0x76, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e,
-	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
-	0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61,
-	0x73, 0x73, 0x22, 0xe6, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x53,
-	0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12,
-	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
-	0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
-	0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
-	0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
-	0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6f, 0x75,
-	0x72, 0x63, 0x65, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1b,
-	0x0a, 0x07, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42,
-	0x02, 0x18, 0x01, 0x52, 0x06, 0x73, 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x1f, 0x0a, 0x0b, 0x61,
-	0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
-	0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03,
-	0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4c, 0x0a, 0x18, 0x43,
-	0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73,
-	0x68, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52,
-	0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0x84, 0x01, 0x0a, 0x0f, 0x52, 0x65,
-	0x73, 0x69, 0x7a, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
+var File_pkg_lvmd_proto_lvmd_proto protoreflect.FileDescriptor
+
+var file_pkg_lvmd_proto_lvmd_proto_rawDesc = []byte{
+	0x0a, 0x19, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x76, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2f, 0x6c, 0x76, 0x6d, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xad, 0x01, 0x0a, 0x0d,
+	0x4c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x12, 0x0a,
 	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
 	0x65, 0x12, 0x1b, 0x0a, 0x07, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x73, 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x1d,
-	0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01,
-	0x28, 0x03, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a,
-	0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73,
-	0x22, 0x43, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4c, 0x56, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73,
-	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73,
-	0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c,
-	0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x07, 0x76, 0x6f,
-	0x6c, 0x75, 0x6d, 0x65, 0x73, 0x22, 0x35, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x46, 0x72, 0x65, 0x65,
-	0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a,
-	0x0a, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x35, 0x0a, 0x10,
-	0x47, 0x65, 0x74, 0x4c, 0x56, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c,
-	0x61, 0x73, 0x73, 0x22, 0x38, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x46, 0x72, 0x65, 0x65, 0x42, 0x79,
-	0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65,
-	0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x22, 0x56, 0x0a,
-	0x0d, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d,
-	0x0a, 0x0a, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x26, 0x0a,
-	0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05,
-	0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xac, 0x01, 0x0a, 0x0c, 0x54, 0x68, 0x69, 0x6e, 0x50, 0x6f,
-	0x6f, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70,
-	0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x64, 0x61,
-	0x74, 0x61, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x65, 0x74,
-	0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x01, 0x52, 0x0f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x65, 0x72,
-	0x63, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x13, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x76,
-	0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x12, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e,
-	0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79,
-	0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42,
-	0x79, 0x74, 0x65, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x09, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, 0x74,
-	0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65,
+	0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x73, 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x1b,
+	0x0a, 0x09, 0x64, 0x65, 0x76, 0x5f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x4d, 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x64,
+	0x65, 0x76, 0x5f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08,
+	0x64, 0x65, 0x76, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73,
+	0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a,
+	0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03,
+	0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0xcc, 0x01, 0x0a, 0x0f,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x07, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x73, 0x69, 0x7a, 0x65, 0x47, 0x62,
+	0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04,
+	0x74, 0x61, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63,
+	0x6c, 0x61, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6c, 0x76, 0x63, 0x72, 0x65,
+	0x61, 0x74, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x6c, 0x76, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
+	0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73,
+	0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x40, 0x0a, 0x10, 0x43, 0x72,
+	0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c,
+	0x0a, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x56, 0x6f,
+	0x6c, 0x75, 0x6d, 0x65, 0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x22, 0x48, 0x0a, 0x0f,
+	0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c,
+	0x61, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63,
+	0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x22, 0xe6, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74,
+	0x65, 0x4c, 0x56, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65,
+	0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x23, 0x0a,
+	0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x6f, 0x6c, 0x75,
+	0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x07, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x73, 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12,
+	0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65,
+	0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22,
+	0x4c, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x53, 0x6e, 0x61, 0x70, 0x73,
+	0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x08, 0x73,
+	0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x56, 0x6f, 0x6c,
+	0x75, 0x6d, 0x65, 0x52, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0x84, 0x01,
+	0x0a, 0x0f, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x07, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x73, 0x69, 0x7a, 0x65,
+	0x47, 0x62, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,
+	0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65,
 	0x73, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73,
-	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43,
-	0x6c, 0x61, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74,
-	0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79,
-	0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x09, 0x74, 0x68, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6f, 0x6c,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54,
-	0x68, 0x69, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x68, 0x69,
-	0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x32, 0x81, 0x02, 0x0a, 0x09, 0x4c, 0x56, 0x53, 0x65, 0x72, 0x76,
-	0x69, 0x63, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x12,
-	0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
-	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x12, 0x30, 0x0a, 0x08, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x56, 0x12, 0x16, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70,
-	0x74, 0x79, 0x12, 0x30, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x4c, 0x56, 0x12, 0x16,
-	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x4c, 0x56, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45,
-	0x6d, 0x70, 0x74, 0x79, 0x12, 0x53, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56,
-	0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f,
-	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f,
-	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc3, 0x01, 0x0a, 0x09, 0x56, 0x47,
-	0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4c, 0x56,
-	0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74,
-	0x4c, 0x56, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x56, 0x4c, 0x69, 0x73, 0x74, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x46, 0x72,
-	0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
-	0x47, 0x65, 0x74, 0x46, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x46,
-	0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x12, 0x2d, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
-	0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42,
-	0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x6f,
-	0x70, 0x6f, 0x6c, 0x76, 0x6d, 0x2f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x76, 0x6d, 0x2f, 0x6c, 0x76,
-	0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43,
+	0x6c, 0x61, 0x73, 0x73, 0x22, 0x43, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4c, 0x56, 0x4c, 0x69, 0x73,
+	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x76, 0x6f, 0x6c,
+	0x75, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65,
+	0x52, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x22, 0x35, 0x0a, 0x14, 0x47, 0x65, 0x74,
+	0x46, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73,
+	0x22, 0x35, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4c, 0x56, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63,
+	0x6c, 0x61, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x22, 0x38, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x46, 0x72,
+	0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21,
+	0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73,
+	0x73, 0x22, 0x56, 0x0a, 0x0d, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65,
+	0x73, 0x12, 0x26, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, 0x74,
+	0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xac, 0x01, 0x0a, 0x0c, 0x54, 0x68,
+	0x69, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x61,
+	0x74, 0x61, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01,
+	0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a,
+	0x10, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e,
+	0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+	0x61, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x13, 0x6f, 0x76, 0x65, 0x72,
+	0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x76, 0x69,
+	0x73, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a,
+	0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73,
+	0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x09, 0x57, 0x61, 0x74,
+	0x63, 0x68, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x62,
+	0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x65,
+	0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
+	0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76,
+	0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65,
+	0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x69,
+	0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x09, 0x74, 0x68, 0x69, 0x6e, 0x5f,
+	0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x54, 0x68, 0x69, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x52,
+	0x08, 0x74, 0x68, 0x69, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x32, 0x81, 0x02, 0x0a, 0x09, 0x4c, 0x56,
+	0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x43, 0x72, 0x65, 0x61, 0x74,
+	0x65, 0x4c, 0x56, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61,
+	0x74, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x08, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x56,
+	0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c,
+	0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x30, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65,
+	0x4c, 0x56, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a,
+	0x65, 0x4c, 0x56, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x53, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61,
+	0x74, 0x65, 0x4c, 0x56, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1e, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x53, 0x6e, 0x61,
+	0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x56, 0x53, 0x6e, 0x61,
+	0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc3, 0x01,
+	0x0a, 0x09, 0x56, 0x47, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x47,
+	0x65, 0x74, 0x4c, 0x56, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2e, 0x47, 0x65, 0x74, 0x4c, 0x56, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x56, 0x4c,
+	0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x47,
+	0x65, 0x74, 0x46, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+	0x47, 0x65, 0x74, 0x46, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x0c, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x30, 0x01, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+	0x6d, 0x2f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x76, 0x6d, 0x2f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x76,
+	0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x76, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
-	file_lvmd_proto_lvmd_proto_rawDescOnce sync.Once
-	file_lvmd_proto_lvmd_proto_rawDescData = file_lvmd_proto_lvmd_proto_rawDesc
+	file_pkg_lvmd_proto_lvmd_proto_rawDescOnce sync.Once
+	file_pkg_lvmd_proto_lvmd_proto_rawDescData = file_pkg_lvmd_proto_lvmd_proto_rawDesc
 )
 
-func file_lvmd_proto_lvmd_proto_rawDescGZIP() []byte {
-	file_lvmd_proto_lvmd_proto_rawDescOnce.Do(func() {
-		file_lvmd_proto_lvmd_proto_rawDescData = protoimpl.X.CompressGZIP(file_lvmd_proto_lvmd_proto_rawDescData)
+func file_pkg_lvmd_proto_lvmd_proto_rawDescGZIP() []byte {
+	file_pkg_lvmd_proto_lvmd_proto_rawDescOnce.Do(func() {
+		file_pkg_lvmd_proto_lvmd_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_lvmd_proto_lvmd_proto_rawDescData)
 	})
-	return file_lvmd_proto_lvmd_proto_rawDescData
+	return file_pkg_lvmd_proto_lvmd_proto_rawDescData
 }
 
-var file_lvmd_proto_lvmd_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
-var file_lvmd_proto_lvmd_proto_goTypes = []interface{}{
+var file_pkg_lvmd_proto_lvmd_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
+var file_pkg_lvmd_proto_lvmd_proto_goTypes = []interface{}{
 	(*Empty)(nil),                    // 0: proto.Empty
 	(*LogicalVolume)(nil),            // 1: proto.LogicalVolume
 	(*CreateLVRequest)(nil),          // 2: proto.CreateLVRequest
@@ -1131,7 +1132,7 @@ var file_lvmd_proto_lvmd_proto_goTypes = []interface{}{
 	(*ThinPoolItem)(nil),             // 13: proto.ThinPoolItem
 	(*WatchItem)(nil),                // 14: proto.WatchItem
 }
-var file_lvmd_proto_lvmd_proto_depIdxs = []int32{
+var file_pkg_lvmd_proto_lvmd_proto_depIdxs = []int32{
 	1,  // 0: proto.CreateLVResponse.volume:type_name -> proto.LogicalVolume
 	1,  // 1: proto.CreateLVSnapshotResponse.snapshot:type_name -> proto.LogicalVolume
 	1,  // 2: proto.GetLVListResponse.volumes:type_name -> proto.LogicalVolume
@@ -1158,13 +1159,13 @@ var file_lvmd_proto_lvmd_proto_depIdxs = []int32{
 	0,  // [0:5] is the sub-list for field type_name
 }
 
-func init() { file_lvmd_proto_lvmd_proto_init() }
-func file_lvmd_proto_lvmd_proto_init() {
-	if File_lvmd_proto_lvmd_proto != nil {
+func init() { file_pkg_lvmd_proto_lvmd_proto_init() }
+func file_pkg_lvmd_proto_lvmd_proto_init() {
+	if File_pkg_lvmd_proto_lvmd_proto != nil {
 		return
 	}
 	if !protoimpl.UnsafeEnabled {
-		file_lvmd_proto_lvmd_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Empty); i {
 			case 0:
 				return &v.state
@@ -1176,7 +1177,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*LogicalVolume); i {
 			case 0:
 				return &v.state
@@ -1188,7 +1189,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*CreateLVRequest); i {
 			case 0:
 				return &v.state
@@ -1200,7 +1201,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*CreateLVResponse); i {
 			case 0:
 				return &v.state
@@ -1212,7 +1213,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*RemoveLVRequest); i {
 			case 0:
 				return &v.state
@@ -1224,7 +1225,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*CreateLVSnapshotRequest); i {
 			case 0:
 				return &v.state
@@ -1236,7 +1237,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*CreateLVSnapshotResponse); i {
 			case 0:
 				return &v.state
@@ -1248,7 +1249,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*ResizeLVRequest); i {
 			case 0:
 				return &v.state
@@ -1260,7 +1261,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*GetLVListResponse); i {
 			case 0:
 				return &v.state
@@ -1272,7 +1273,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*GetFreeBytesResponse); i {
 			case 0:
 				return &v.state
@@ -1284,7 +1285,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*GetLVListRequest); i {
 			case 0:
 				return &v.state
@@ -1296,7 +1297,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*GetFreeBytesRequest); i {
 			case 0:
 				return &v.state
@@ -1308,7 +1309,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*WatchResponse); i {
 			case 0:
 				return &v.state
@@ -1320,7 +1321,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*ThinPoolItem); i {
 			case 0:
 				return &v.state
@@ -1332,7 +1333,7 @@ func file_lvmd_proto_lvmd_proto_init() {
 				return nil
 			}
 		}
-		file_lvmd_proto_lvmd_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_lvmd_proto_lvmd_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*WatchItem); i {
 			case 0:
 				return &v.state
@@ -1349,18 +1350,18 @@ func file_lvmd_proto_lvmd_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_lvmd_proto_lvmd_proto_rawDesc,
+			RawDescriptor: file_pkg_lvmd_proto_lvmd_proto_rawDesc,
 			NumEnums:      0,
 			NumMessages:   15,
 			NumExtensions: 0,
 			NumServices:   2,
 		},
-		GoTypes:           file_lvmd_proto_lvmd_proto_goTypes,
-		DependencyIndexes: file_lvmd_proto_lvmd_proto_depIdxs,
-		MessageInfos:      file_lvmd_proto_lvmd_proto_msgTypes,
+		GoTypes:           file_pkg_lvmd_proto_lvmd_proto_goTypes,
+		DependencyIndexes: file_pkg_lvmd_proto_lvmd_proto_depIdxs,
+		MessageInfos:      file_pkg_lvmd_proto_lvmd_proto_msgTypes,
 	}.Build()
-	File_lvmd_proto_lvmd_proto = out.File
-	file_lvmd_proto_lvmd_proto_rawDesc = nil
-	file_lvmd_proto_lvmd_proto_goTypes = nil
-	file_lvmd_proto_lvmd_proto_depIdxs = nil
+	File_pkg_lvmd_proto_lvmd_proto = out.File
+	file_pkg_lvmd_proto_lvmd_proto_rawDesc = nil
+	file_pkg_lvmd_proto_lvmd_proto_goTypes = nil
+	file_pkg_lvmd_proto_lvmd_proto_depIdxs = nil
 }
diff --git a/lvmd/proto/lvmd.proto b/pkg/lvmd/proto/lvmd.proto
similarity index 98%
rename from lvmd/proto/lvmd.proto
rename to pkg/lvmd/proto/lvmd.proto
index 4a918b91..1e4713c3 100644
--- a/lvmd/proto/lvmd.proto
+++ b/pkg/lvmd/proto/lvmd.proto
@@ -8,7 +8,7 @@
 syntax = "proto3";
 package proto;
 
-option go_package = "github.com/topolvm/topolvm/lvmd/proto";
+option go_package = "github.com/topolvm/topolvm/pkg/lvmd/proto";
 
 message Empty {}
 
diff --git a/lvmd/proto/lvmd_grpc.pb.go b/pkg/lvmd/proto/lvmd_grpc.pb.go
similarity index 88%
rename from lvmd/proto/lvmd_grpc.pb.go
rename to pkg/lvmd/proto/lvmd_grpc.pb.go
index fcc1b707..ecd1da8c 100644
--- a/lvmd/proto/lvmd_grpc.pb.go
+++ b/pkg/lvmd/proto/lvmd_grpc.pb.go
@@ -1,8 +1,15 @@
+//*
+// LVMd manages logical volumes of an LVM volume group.
+//
+// The protocol consists of two services:
+// - VGService provides information of the volume group.
+// - LVService provides management functions for logical volumes on the volume group.
+
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
-// - protoc-gen-go-grpc v1.2.0
-// - protoc             v4.24.4
-// source: lvmd/proto/lvmd.proto
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v4.25.2
+// source: pkg/lvmd/proto/lvmd.proto
 
 package proto
 
@@ -18,6 +25,13 @@ import (
 // Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
+const (
+	LVService_CreateLV_FullMethodName         = "/proto.LVService/CreateLV"
+	LVService_RemoveLV_FullMethodName         = "/proto.LVService/RemoveLV"
+	LVService_ResizeLV_FullMethodName         = "/proto.LVService/ResizeLV"
+	LVService_CreateLVSnapshot_FullMethodName = "/proto.LVService/CreateLVSnapshot"
+)
+
 // LVServiceClient is the client API for LVService service.
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -41,7 +55,7 @@ func NewLVServiceClient(cc grpc.ClientConnInterface) LVServiceClient {
 
 func (c *lVServiceClient) CreateLV(ctx context.Context, in *CreateLVRequest, opts ...grpc.CallOption) (*CreateLVResponse, error) {
 	out := new(CreateLVResponse)
-	err := c.cc.Invoke(ctx, "/proto.LVService/CreateLV", in, out, opts...)
+	err := c.cc.Invoke(ctx, LVService_CreateLV_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -50,7 +64,7 @@ func (c *lVServiceClient) CreateLV(ctx context.Context, in *CreateLVRequest, opt
 
 func (c *lVServiceClient) RemoveLV(ctx context.Context, in *RemoveLVRequest, opts ...grpc.CallOption) (*Empty, error) {
 	out := new(Empty)
-	err := c.cc.Invoke(ctx, "/proto.LVService/RemoveLV", in, out, opts...)
+	err := c.cc.Invoke(ctx, LVService_RemoveLV_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -59,7 +73,7 @@ func (c *lVServiceClient) RemoveLV(ctx context.Context, in *RemoveLVRequest, opt
 
 func (c *lVServiceClient) ResizeLV(ctx context.Context, in *ResizeLVRequest, opts ...grpc.CallOption) (*Empty, error) {
 	out := new(Empty)
-	err := c.cc.Invoke(ctx, "/proto.LVService/ResizeLV", in, out, opts...)
+	err := c.cc.Invoke(ctx, LVService_ResizeLV_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -68,7 +82,7 @@ func (c *lVServiceClient) ResizeLV(ctx context.Context, in *ResizeLVRequest, opt
 
 func (c *lVServiceClient) CreateLVSnapshot(ctx context.Context, in *CreateLVSnapshotRequest, opts ...grpc.CallOption) (*CreateLVSnapshotResponse, error) {
 	out := new(CreateLVSnapshotResponse)
-	err := c.cc.Invoke(ctx, "/proto.LVService/CreateLVSnapshot", in, out, opts...)
+	err := c.cc.Invoke(ctx, LVService_CreateLVSnapshot_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -128,7 +142,7 @@ func _LVService_CreateLV_Handler(srv interface{}, ctx context.Context, dec func(
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/proto.LVService/CreateLV",
+		FullMethod: LVService_CreateLV_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(LVServiceServer).CreateLV(ctx, req.(*CreateLVRequest))
@@ -146,7 +160,7 @@ func _LVService_RemoveLV_Handler(srv interface{}, ctx context.Context, dec func(
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/proto.LVService/RemoveLV",
+		FullMethod: LVService_RemoveLV_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(LVServiceServer).RemoveLV(ctx, req.(*RemoveLVRequest))
@@ -164,7 +178,7 @@ func _LVService_ResizeLV_Handler(srv interface{}, ctx context.Context, dec func(
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/proto.LVService/ResizeLV",
+		FullMethod: LVService_ResizeLV_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(LVServiceServer).ResizeLV(ctx, req.(*ResizeLVRequest))
@@ -182,7 +196,7 @@ func _LVService_CreateLVSnapshot_Handler(srv interface{}, ctx context.Context, d
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/proto.LVService/CreateLVSnapshot",
+		FullMethod: LVService_CreateLVSnapshot_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(LVServiceServer).CreateLVSnapshot(ctx, req.(*CreateLVSnapshotRequest))
@@ -215,9 +229,15 @@ var LVService_ServiceDesc = grpc.ServiceDesc{
 		},
 	},
 	Streams:  []grpc.StreamDesc{},
-	Metadata: "lvmd/proto/lvmd.proto",
+	Metadata: "pkg/lvmd/proto/lvmd.proto",
 }
 
+const (
+	VGService_GetLVList_FullMethodName    = "/proto.VGService/GetLVList"
+	VGService_GetFreeBytes_FullMethodName = "/proto.VGService/GetFreeBytes"
+	VGService_Watch_FullMethodName        = "/proto.VGService/Watch"
+)
+
 // VGServiceClient is the client API for VGService service.
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -240,7 +260,7 @@ func NewVGServiceClient(cc grpc.ClientConnInterface) VGServiceClient {
 
 func (c *vGServiceClient) GetLVList(ctx context.Context, in *GetLVListRequest, opts ...grpc.CallOption) (*GetLVListResponse, error) {
 	out := new(GetLVListResponse)
-	err := c.cc.Invoke(ctx, "/proto.VGService/GetLVList", in, out, opts...)
+	err := c.cc.Invoke(ctx, VGService_GetLVList_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -249,7 +269,7 @@ func (c *vGServiceClient) GetLVList(ctx context.Context, in *GetLVListRequest, o
 
 func (c *vGServiceClient) GetFreeBytes(ctx context.Context, in *GetFreeBytesRequest, opts ...grpc.CallOption) (*GetFreeBytesResponse, error) {
 	out := new(GetFreeBytesResponse)
-	err := c.cc.Invoke(ctx, "/proto.VGService/GetFreeBytes", in, out, opts...)
+	err := c.cc.Invoke(ctx, VGService_GetFreeBytes_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -257,7 +277,7 @@ func (c *vGServiceClient) GetFreeBytes(ctx context.Context, in *GetFreeBytesRequ
 }
 
 func (c *vGServiceClient) Watch(ctx context.Context, in *Empty, opts ...grpc.CallOption) (VGService_WatchClient, error) {
-	stream, err := c.cc.NewStream(ctx, &VGService_ServiceDesc.Streams[0], "/proto.VGService/Watch", opts...)
+	stream, err := c.cc.NewStream(ctx, &VGService_ServiceDesc.Streams[0], VGService_Watch_FullMethodName, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -337,7 +357,7 @@ func _VGService_GetLVList_Handler(srv interface{}, ctx context.Context, dec func
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/proto.VGService/GetLVList",
+		FullMethod: VGService_GetLVList_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(VGServiceServer).GetLVList(ctx, req.(*GetLVListRequest))
@@ -355,7 +375,7 @@ func _VGService_GetFreeBytes_Handler(srv interface{}, ctx context.Context, dec f
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/proto.VGService/GetFreeBytes",
+		FullMethod: VGService_GetFreeBytes_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(VGServiceServer).GetFreeBytes(ctx, req.(*GetFreeBytesRequest))
@@ -407,5 +427,5 @@ var VGService_ServiceDesc = grpc.ServiceDesc{
 			ServerStreams: true,
 		},
 	},
-	Metadata: "lvmd/proto/lvmd.proto",
+	Metadata: "pkg/lvmd/proto/lvmd.proto",
 }
diff --git a/pkg/lvmd/types/types.go b/pkg/lvmd/types/types.go
new file mode 100644
index 00000000..c5182a55
--- /dev/null
+++ b/pkg/lvmd/types/types.go
@@ -0,0 +1,46 @@
+package types
+
+type DeviceType string
+
+const (
+	TypeThin  = DeviceType("thin")
+	TypeThick = DeviceType("thick")
+)
+
+// ThinPoolConfig holds the configuration of thin pool in a volume group
+type ThinPoolConfig struct {
+	// Name of thinpool
+	Name string `json:"name"`
+	// OverprovisionRatio signifies the upper bound multiplier for allowing logical volume creation in this pool
+	OverprovisionRatio float64 `json:"overprovision-ratio"`
+}
+
+// DeviceClass maps between device-classes and target for logical volume creation
+// current targets are VolumeGroup for thick-lv and ThinPool for thin-lv
+type DeviceClass struct {
+	// Name for the device-class name
+	Name string `json:"name"`
+	// Volume group name for the device-class
+	VolumeGroup string `json:"volume-group"`
+	// Default is a flag to indicate whether the device-class is the default
+	Default bool `json:"default"`
+	// SpareGB is storage capacity in GiB to be spared
+	SpareGB *uint64 `json:"spare-gb"`
+	// Stripe is the number of stripes in the logical volume
+	Stripe *uint `json:"stripe"`
+	// StripeSize is the amount of data that is written to one device before moving to the next device
+	StripeSize string `json:"stripe-size"`
+	// LVCreateOptions are extra arguments to pass to lvcreate
+	LVCreateOptions []string `json:"lvcreate-options"`
+	// Type is the name of logical volume target, supports 'thick' (default) or 'thin' currently
+	Type DeviceType `json:"type"`
+	// ThinPoolConfig holds the configuration for thinpool in this volume group corresponding to the device-class
+	ThinPoolConfig *ThinPoolConfig `json:"thin-pool"`
+}
+
+type LvcreateOptionClass struct {
+	// Name for the lvcreate-option-class name
+	Name string `json:"name"`
+	// Options are extra arguments to pass to lvcreate
+	Options []string `json:"options"`
+}
diff --git a/pkg/runners/grpc.go b/pkg/runners/grpc.go
new file mode 100644
index 00000000..be3e48db
--- /dev/null
+++ b/pkg/runners/grpc.go
@@ -0,0 +1,7 @@
+package runners
+
+import (
+	internalRunners "github.com/topolvm/topolvm/internal/runners"
+)
+
+var NewGRPCRunner = internalRunners.NewGRPCRunner
diff --git a/pkg/runners/metrics_exporter.go b/pkg/runners/metrics_exporter.go
new file mode 100644
index 00000000..65c20709
--- /dev/null
+++ b/pkg/runners/metrics_exporter.go
@@ -0,0 +1,7 @@
+package runners
+
+import (
+	internalRunners "github.com/topolvm/topolvm/internal/runners"
+)
+
+var NewMetricsExporter = internalRunners.NewMetricsExporter
diff --git a/pkg/topolvm-controller/main.go b/pkg/topolvm-controller/main.go
deleted file mode 100644
index c24c05f3..00000000
--- a/pkg/topolvm-controller/main.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package main
-
-import "github.com/topolvm/topolvm/pkg/topolvm-controller/cmd"
-
-func main() {
-	cmd.Execute()
-}
diff --git a/pkg/topolvm-scheduler/main.go b/pkg/topolvm-scheduler/main.go
deleted file mode 100644
index c3ae6679..00000000
--- a/pkg/topolvm-scheduler/main.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package main
-
-import "github.com/topolvm/topolvm/pkg/topolvm-scheduler/cmd"
-
-func main() {
-	cmd.Execute()
-}


Test patch:
diff --git a/.github/workflows/e2e-k8s-incluster-lvmd.yaml b/.github/workflows/e2e-k8s-incluster-lvmd.yaml
index 0f4b8186..bb8c18f3 100644
--- a/.github/workflows/e2e-k8s-incluster-lvmd.yaml
+++ b/.github/workflows/e2e-k8s-incluster-lvmd.yaml
@@ -43,11 +43,11 @@ jobs:
         uses: actions/cache@v4
         with:
           path: |
-            e2e/tmpbin
+            test/e2e/tmpbin
           key: e2e-sidecars-${{ hashFiles('csi-sidecars.mk', 'versions.mk') }}
           restore-keys: |
             e2e-sidecars-
-      - run: make -C e2e incluster-lvmd/create-vg
-      - run: make -C e2e incluster-lvmd/setup-minikube
-      - run: make -C e2e incluster-lvmd/launch-minikube
-      - run: make -C e2e incluster-lvmd/test
+      - run: make -C test/e2e incluster-lvmd/create-vg
+      - run: make -C test/e2e incluster-lvmd/setup-minikube
+      - run: make -C test/e2e incluster-lvmd/launch-minikube
+      - run: make -C test/e2e incluster-lvmd/test
diff --git a/.github/workflows/e2e-k8s-workflow.yaml b/.github/workflows/e2e-k8s-workflow.yaml
index 8491a7ed..4074b392 100644
--- a/.github/workflows/e2e-k8s-workflow.yaml
+++ b/.github/workflows/e2e-k8s-workflow.yaml
@@ -36,9 +36,9 @@ jobs:
         with:
           path: |
             bin
-            e2e/bin
-            e2e/topolvm.img
+            test/e2e/bin
+            test/e2e/topolvm.img
           key: e2e-cache-${{ github.sha }}
-      - run: touch e2e/topolvm.img # update timestamp not to rebuild image
-      - run: make -C e2e start-lvmd
-      - run: make -C e2e test
+      - run: touch test/e2e/topolvm.img # update timestamp not to rebuild image
+      - run: make -C test/e2e start-lvmd
+      - run: make -C test/e2e test
diff --git a/.github/workflows/e2e-k8s.yaml b/.github/workflows/e2e-k8s.yaml
index d9be63e9..2b8b184a 100644
--- a/.github/workflows/e2e-k8s.yaml
+++ b/.github/workflows/e2e-k8s.yaml
@@ -34,18 +34,18 @@ jobs:
         uses: actions/cache@v4
         with:
           path: |
-            e2e/tmpbin
+            test/e2e/tmpbin
           key: e2e-sidecars-${{ hashFiles('csi-sidecars.mk', 'versions.mk') }}
           restore-keys: |
             e2e-sidecars-
-      - run: make -C e2e setup
-      - run: make -C e2e topolvm.img
+      - run: make -C test/e2e setup
+      - run: make -C test/e2e topolvm.img
       - uses: actions/cache/save@v4
         with:
           path: |
             bin
-            e2e/bin
-            e2e/topolvm.img
+            test/e2e/bin
+            test/e2e/topolvm.img
           key: e2e-cache-${{ github.sha }}
 
   default:
diff --git a/pkg/topolvm-scheduler/cmd/access_log_test.go b/cmd/topolvm-scheduler/app/access_log_test.go
similarity index 99%
rename from pkg/topolvm-scheduler/cmd/access_log_test.go
rename to cmd/topolvm-scheduler/app/access_log_test.go
index 7801df03..9f4258aa 100644
--- a/pkg/topolvm-scheduler/cmd/access_log_test.go
+++ b/cmd/topolvm-scheduler/app/access_log_test.go
@@ -1,4 +1,4 @@
-package cmd
+package app
 
 import (
 	"context"
diff --git a/constants_test.go b/constants_test.go
index 9973753b..3aa576bf 100644
--- a/constants_test.go
+++ b/constants_test.go
@@ -7,7 +7,7 @@ import (
 	"strings"
 	"testing"
 
-	testingutil "github.com/topolvm/topolvm/util/testing"
+	testingutil "github.com/topolvm/topolvm/test/util"
 )
 
 func TestUseLegacy(t *testing.T) {
diff --git a/client/client.go b/internal/client/client.go
similarity index 100%
rename from client/client.go
rename to internal/client/client.go
diff --git a/client/client_test.go b/internal/client/client_test.go
similarity index 100%
rename from client/client_test.go
rename to internal/client/client_test.go
diff --git a/client/suite_test.go b/internal/client/suite_test.go
similarity index 97%
rename from client/suite_test.go
rename to internal/client/suite_test.go
index b4dc905c..5b83c2e9 100644
--- a/client/suite_test.go
+++ b/internal/client/suite_test.go
@@ -12,7 +12,7 @@ import (
 	"github.com/topolvm/topolvm"
 	topolvmlegacyv1 "github.com/topolvm/topolvm/api/legacy/v1"
 	topolvmv1 "github.com/topolvm/topolvm/api/v1"
-	testingutil "github.com/topolvm/topolvm/util/testing"
+	testingutil "github.com/topolvm/topolvm/test/util"
 	"google.golang.org/grpc/codes"
 
 	"k8s.io/apimachinery/pkg/api/resource"
@@ -57,7 +57,7 @@ var _ = BeforeSuite(func() {
 
 	By("bootstrapping test environment")
 	testEnv = &envtest.Environment{
-		CRDDirectoryPaths:     []string{filepath.Join("..", "config", "crd", "bases")},
+		CRDDirectoryPaths:     []string{filepath.Join("..", "..", "config", "crd", "bases")},
 		ErrorIfCRDPathMissing: true,
 	}
 
diff --git a/controllers/logicalvolume_controller_test.go b/internal/controller/logicalvolume_controller_test.go
similarity index 99%
rename from controllers/logicalvolume_controller_test.go
rename to internal/controller/logicalvolume_controller_test.go
index 911dc5ad..7c63841a 100644
--- a/controllers/logicalvolume_controller_test.go
+++ b/internal/controller/logicalvolume_controller_test.go
@@ -1,4 +1,4 @@
-package controllers
+package controller
 
 import (
 	"context"
@@ -8,7 +8,7 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/topolvm/topolvm"
 	topolvmv1 "github.com/topolvm/topolvm/api/v1"
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
 	"google.golang.org/grpc"
 	corev1 "k8s.io/api/core/v1"
 	storegev1 "k8s.io/api/storage/v1"
diff --git a/controllers/node_controller_test.go b/internal/controller/node_controller_test.go
similarity index 99%
rename from controllers/node_controller_test.go
rename to internal/controller/node_controller_test.go
index 15f880ac..574c3c81 100644
--- a/controllers/node_controller_test.go
+++ b/internal/controller/node_controller_test.go
@@ -1,4 +1,4 @@
-package controllers
+package controller
 
 import (
 	"context"
diff --git a/controllers/persistentvolumeclaim_controller_test.go b/internal/controller/persistentvolumeclaim_controller_test.go
similarity index 99%
rename from controllers/persistentvolumeclaim_controller_test.go
rename to internal/controller/persistentvolumeclaim_controller_test.go
index 9d4b6527..dc0b7ba7 100644
--- a/controllers/persistentvolumeclaim_controller_test.go
+++ b/internal/controller/persistentvolumeclaim_controller_test.go
@@ -1,4 +1,4 @@
-package controllers
+package controller
 
 import (
 	"context"
diff --git a/controllers/suite_test.go b/internal/controller/suite_test.go
similarity index 95%
rename from controllers/suite_test.go
rename to internal/controller/suite_test.go
index 77e1747e..2a4437ad 100644
--- a/controllers/suite_test.go
+++ b/internal/controller/suite_test.go
@@ -1,4 +1,4 @@
-package controllers
+package controller
 
 import (
 	"context"
@@ -58,7 +58,7 @@ var _ = BeforeSuite(func() {
 
 	By("bootstrapping test environment")
 	testEnv = &envtest.Environment{
-		CRDDirectoryPaths:     []string{filepath.Join("..", "config", "crd", "bases")},
+		CRDDirectoryPaths:     []string{filepath.Join("..", "..", "config", "crd", "bases")},
 		ErrorIfCRDPathMissing: true,
 	}
 
diff --git a/hook/mutate_pod_test.go b/internal/hook/mutate_pod_test.go
similarity index 100%
rename from hook/mutate_pod_test.go
rename to internal/hook/mutate_pod_test.go
diff --git a/hook/run_test.go b/internal/hook/run_test.go
similarity index 100%
rename from hook/run_test.go
rename to internal/hook/run_test.go
diff --git a/hook/suite_test.go b/internal/hook/suite_test.go
similarity index 98%
rename from hook/suite_test.go
rename to internal/hook/suite_test.go
index 2307b25b..d70520b9 100644
--- a/hook/suite_test.go
+++ b/internal/hook/suite_test.go
@@ -191,7 +191,7 @@ var _ = BeforeSuite(func() {
 	}
 
 	testEnv = &envtest.Environment{
-		CRDDirectoryPaths:     []string{filepath.Join("..", "config", "crd", "bases")},
+		CRDDirectoryPaths:     []string{filepath.Join("..", "..", "config", "crd", "bases")},
 		WebhookInstallOptions: webhookInstallOptions,
 	}
 
diff --git a/lvmd/command/lvm.go b/internal/lvmd/command/lvm.go
similarity index 100%
rename from lvmd/command/lvm.go
rename to internal/lvmd/command/lvm.go
diff --git a/lvmd/command/lvm_command.go b/internal/lvmd/command/lvm_command.go
similarity index 100%
rename from lvmd/command/lvm_command.go
rename to internal/lvmd/command/lvm_command.go
diff --git a/lvmd/command/lvm_command_test.go b/internal/lvmd/command/lvm_command_test.go
similarity index 100%
rename from lvmd/command/lvm_command_test.go
rename to internal/lvmd/command/lvm_command_test.go
diff --git a/lvmd/command/lvm_lvs.go b/internal/lvmd/command/lvm_lvs.go
similarity index 100%
rename from lvmd/command/lvm_lvs.go
rename to internal/lvmd/command/lvm_lvs.go
diff --git a/lvmd/command/lvm_state_json.go b/internal/lvmd/command/lvm_state_json.go
similarity index 100%
rename from lvmd/command/lvm_state_json.go
rename to internal/lvmd/command/lvm_state_json.go
diff --git a/lvmd/command/lvm_state_json_test.go b/internal/lvmd/command/lvm_state_json_test.go
similarity index 99%
rename from lvmd/command/lvm_state_json_test.go
rename to internal/lvmd/command/lvm_state_json_test.go
index f31988d2..87989aba 100644
--- a/lvmd/command/lvm_state_json_test.go
+++ b/internal/lvmd/command/lvm_state_json_test.go
@@ -8,7 +8,7 @@ import (
 	"testing"
 
 	"github.com/go-logr/logr/testr"
-	"github.com/topolvm/topolvm/lvmd/testutils"
+	"github.com/topolvm/topolvm/internal/lvmd/testutils"
 	ctrl "sigs.k8s.io/controller-runtime"
 )
 
diff --git a/lvmd/device_class_manager_test.go b/internal/lvmd/device_class_manager_test.go
similarity index 76%
rename from lvmd/device_class_manager_test.go
rename to internal/lvmd/device_class_manager_test.go
index e54fcd11..da79230a 100644
--- a/lvmd/device_class_manager_test.go
+++ b/internal/lvmd/device_class_manager_test.go
@@ -3,6 +3,8 @@ package lvmd
 import (
 	"strconv"
 	"testing"
+
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 )
 
 func TestValidateDeviceClasses(t *testing.T) {
@@ -11,11 +13,11 @@ func TestValidateDeviceClasses(t *testing.T) {
 	wrongOpRatio := float64(0.5)
 
 	cases := []struct {
-		deviceClasses []*DeviceClass
+		deviceClasses []*lvmdTypes.DeviceClass
 		valid         bool
 	}{
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:        "dc1",
 					VolumeGroup: "node1-myvg1",
@@ -29,7 +31,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: true,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:        "stripe-size",
 					VolumeGroup: "node1-myvg1",
@@ -41,7 +43,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: true,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:        "stripe-size-with-unit1",
 					VolumeGroup: "node1-myvg1",
@@ -59,7 +61,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: true,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:            "extra-options",
 					VolumeGroup:     "node1-myvg1",
@@ -77,14 +79,14 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: true,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					// dev0 -> vg0/pool0
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool0",
 						OverprovisionRatio: opRatio,
 					},
@@ -94,8 +96,8 @@ func TestValidateDeviceClasses(t *testing.T) {
 					// same volume group as in dev0
 					Name:        "dev1",
 					VolumeGroup: "vg0",
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool1",
 						OverprovisionRatio: opRatio,
 					},
@@ -106,8 +108,8 @@ func TestValidateDeviceClasses(t *testing.T) {
 					// name as in dev0
 					Name:        "dev3",
 					VolumeGroup: "vg1",
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool0",
 						OverprovisionRatio: opRatio,
 					},
@@ -116,14 +118,14 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: true,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					// dev0 -> vg0/pool0
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool0",
 						OverprovisionRatio: opRatio,
 					},
@@ -133,15 +135,15 @@ func TestValidateDeviceClasses(t *testing.T) {
 					// same volume group as in dev0 with Type specified
 					Name:        "dev1",
 					VolumeGroup: "vg0",
-					Type:        TypeThick,
+					Type:        lvmdTypes.TypeThick,
 				},
 				{
 					// dev2 -> vg1/pool0
 					// different vg and different pool
 					Name:        "dev2",
 					VolumeGroup: "vg1",
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool1",
 						OverprovisionRatio: opRatio,
 					},
@@ -157,14 +159,14 @@ func TestValidateDeviceClasses(t *testing.T) {
 		},
 		{
 			// ThinPoolConfig should be ignored if Type is TypeThick
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					// dev0 -> vg0 since Type is TypeThick
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        TypeThick,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThick,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name: "pool0",
 					},
 				},
@@ -172,7 +174,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: true,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:        "__invalid-device-class-name__",
 					VolumeGroup: "node1-myvg1",
@@ -182,7 +184,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:        "duplicate-name",
 					VolumeGroup: "node1-myvg1",
@@ -196,7 +198,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:        "dc1",
 					VolumeGroup: "node1-myvg1",
@@ -209,7 +211,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: true,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:        "dc1",
 					VolumeGroup: "node1-myvg1",
@@ -224,11 +226,11 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{},
+			deviceClasses: []*lvmdTypes.DeviceClass{},
 			valid:         false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				{
 					Name:        "invalid-stripe-size",
 					VolumeGroup: "node1-myvg1",
@@ -240,7 +242,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				// effectively pointing to same volume group, since empty Type or
 				// TypeThick considers thick volume creation on volume group
 				{
@@ -248,8 +250,8 @@ func TestValidateDeviceClasses(t *testing.T) {
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        TypeThick,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThick,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name: "pool0",
 					},
 				},
@@ -257,7 +259,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 					// dev1 -> vg0
 					Name:        "dev1",
 					VolumeGroup: "vg0",
-					ThinPoolConfig: &ThinPoolConfig{
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						OverprovisionRatio: opRatio,
 					},
 				},
@@ -265,14 +267,14 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				// incomplete thinpool info, no OverprovisionRatio
 				{
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name: "pool0",
 					},
 				},
@@ -280,14 +282,14 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				// incomplete thinpool info, no thinpool Name
 				{
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						OverprovisionRatio: opRatio,
 					},
 				},
@@ -295,26 +297,26 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				// no thinpool info
 				{
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        TypeThin,
+					Type:        lvmdTypes.TypeThin,
 				},
 			},
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				// overprovision ratio should be > 1.0
 				{
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool0",
 						OverprovisionRatio: wrongOpRatio,
 					},
@@ -323,14 +325,14 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				// incorrect device-class target type
 				{
 					Name:        "dev0",
 					VolumeGroup: "vg0",
 					Default:     true,
-					Type:        DeviceType("dummy"),
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.DeviceType("dummy"),
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool0",
 						OverprovisionRatio: wrongOpRatio,
 					},
@@ -339,7 +341,7 @@ func TestValidateDeviceClasses(t *testing.T) {
 			valid: false,
 		},
 		{
-			deviceClasses: []*DeviceClass{
+			deviceClasses: []*lvmdTypes.DeviceClass{
 				// duplicate thin pools
 				{
 					// dev0 -> vg0
@@ -351,8 +353,8 @@ func TestValidateDeviceClasses(t *testing.T) {
 					// dev1 -> vg0/pool0
 					Name:        "dev1",
 					VolumeGroup: "vg0",
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool0",
 						OverprovisionRatio: opRatio,
 					},
@@ -361,8 +363,8 @@ func TestValidateDeviceClasses(t *testing.T) {
 					// dev2 -> vg0/pool0
 					Name:        "dev2",
 					VolumeGroup: "vg0",
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               "pool0",
 						OverprovisionRatio: opRatio,
 					},
@@ -387,7 +389,7 @@ func TestDeviceClassManager(t *testing.T) {
 	spare100gb := uint64(100)
 	opRatio := float64(10.0)
 	lvcreateOptions := []string{"--mirrors=1"}
-	deviceClasses := []*DeviceClass{
+	deviceClasses := []*lvmdTypes.DeviceClass{
 		{
 			Name:        "dc1",
 			VolumeGroup: "vg1",
@@ -413,8 +415,8 @@ func TestDeviceClassManager(t *testing.T) {
 			Name:        "dev0",
 			VolumeGroup: "vg0",
 			SpareGB:     &spare100gb,
-			Type:        TypeThin,
-			ThinPoolConfig: &ThinPoolConfig{
+			Type:        lvmdTypes.TypeThin,
+			ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 				Name:               "pool0",
 				OverprovisionRatio: opRatio,
 			},
@@ -426,7 +428,7 @@ func TestDeviceClassManager(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	if dc.GetSpare() != spare50gb<<30 {
+	if GetSpare(dc) != spare50gb<<30 {
 		t.Error("dc2's spare should be 50GB")
 	}
 
@@ -439,7 +441,7 @@ func TestDeviceClassManager(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	if dc.GetSpare() != spare100gb<<30 {
+	if GetSpare(dc) != spare100gb<<30 {
 		t.Error("dc3's spare should be 100GB")
 	}
 
@@ -465,10 +467,10 @@ func TestDeviceClassManager(t *testing.T) {
 	if dc.Name != "dc1" {
 		t.Fatal("wrong device-class found")
 	}
-	if dc.GetSpare() != defaultSpareGB<<30 {
+	if GetSpare(dc) != defaultSpareGB<<30 {
 		t.Error("dc1's spare should be default")
 	}
-	if dc.Type != TypeThick {
+	if dc.Type != lvmdTypes.TypeThick {
 		t.Error("Default type should be TypeThick")
 	}
 
diff --git a/lvmd/embed_test.go b/internal/lvmd/embed_test.go
similarity index 78%
rename from lvmd/embed_test.go
rename to internal/lvmd/embed_test.go
index 50220529..d64a5b1a 100644
--- a/lvmd/embed_test.go
+++ b/internal/lvmd/embed_test.go
@@ -4,28 +4,29 @@ import (
 	"context"
 	"testing"
 
-	"github.com/topolvm/topolvm/lvmd/proto"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 )
 
 func TestNewEmbeddedServiceClients(t *testing.T) {
 	overprovisionRatio := float64(2.0)
 	tests := []struct {
 		name          string
-		deviceClasses []*DeviceClass
+		deviceClasses []*lvmdTypes.DeviceClass
 	}{
 
-		{"volumegroup", []*DeviceClass{
+		{"volumegroup", []*lvmdTypes.DeviceClass{
 			{
 				Name:        "dc",
 				VolumeGroup: "test_vgservice",
 			}},
 		},
-		{"thinpool", []*DeviceClass{
+		{"thinpool", []*lvmdTypes.DeviceClass{
 			{
 				Name:        "dc",
 				VolumeGroup: "test_vgservice",
-				Type:        TypeThin,
-				ThinPoolConfig: &ThinPoolConfig{
+				Type:        lvmdTypes.TypeThin,
+				ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 					Name:               "test_pool",
 					OverprovisionRatio: overprovisionRatio,
 				},
diff --git a/lvmd/lvcreate_option_class_manager_test.go b/internal/lvmd/lvcreate_option_class_manager_test.go
similarity index 74%
rename from lvmd/lvcreate_option_class_manager_test.go
rename to internal/lvmd/lvcreate_option_class_manager_test.go
index 0c4009c9..c840ba7d 100644
--- a/lvmd/lvcreate_option_class_manager_test.go
+++ b/internal/lvmd/lvcreate_option_class_manager_test.go
@@ -3,18 +3,20 @@ package lvmd
 import (
 	"strconv"
 	"testing"
+
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 )
 
 func TestLvcreateOptionClassManager(t *testing.T) {
 	cases := []struct {
 		found                 bool
 		name                  string
-		lvcreateOptionClasses []*LvcreateOptionClass
+		lvcreateOptionClasses []*lvmdTypes.LvcreateOptionClass
 	}{
 		{
 			found: true,
 			name:  "option",
-			lvcreateOptionClasses: []*LvcreateOptionClass{
+			lvcreateOptionClasses: []*lvmdTypes.LvcreateOptionClass{
 				{
 					Name:    "option",
 					Options: []string{"--type=raid1"},
@@ -24,7 +26,7 @@ func TestLvcreateOptionClassManager(t *testing.T) {
 		{
 			found: false,
 			name:  "not-found",
-			lvcreateOptionClasses: []*LvcreateOptionClass{
+			lvcreateOptionClasses: []*lvmdTypes.LvcreateOptionClass{
 				{
 					Name:    "option",
 					Options: []string{"--type=raid1"},
diff --git a/lvmd/lvservice_test.go b/internal/lvmd/lvservice_test.go
similarity index 96%
rename from lvmd/lvservice_test.go
rename to internal/lvmd/lvservice_test.go
index caa70a87..fc252cf0 100644
--- a/lvmd/lvservice_test.go
+++ b/internal/lvmd/lvservice_test.go
@@ -8,9 +8,10 @@ import (
 	"testing"
 
 	"github.com/go-logr/logr/testr"
-	"github.com/topolvm/topolvm/lvmd/command"
-	"github.com/topolvm/topolvm/lvmd/proto"
-	"github.com/topolvm/topolvm/lvmd/testutils"
+	"github.com/topolvm/topolvm/internal/lvmd/command"
+	"github.com/topolvm/topolvm/internal/lvmd/testutils"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	ctrl "sigs.k8s.io/controller-runtime"
@@ -58,7 +59,7 @@ func TestLVService(t *testing.T) {
 	thindev := poolName
 	lvService := NewLVService(
 		NewDeviceClassManager(
-			[]*DeviceClass{
+			[]*lvmdTypes.DeviceClass{
 				{
 					// volumegroup target
 					Name:        thickdev,
@@ -68,14 +69,14 @@ func TestLVService(t *testing.T) {
 					// thinpool target
 					Name:        thindev,
 					VolumeGroup: vg.Name(),
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               poolName,
 						OverprovisionRatio: overprovisionRatio,
 					},
 				},
 			},
-		), NewLvcreateOptionClassManager([]*LvcreateOptionClass{}), notifier)
+		), NewLvcreateOptionClassManager([]*lvmdTypes.LvcreateOptionClass{}), notifier)
 
 	// thick logical volume validations
 	res, err := lvService.CreateLV(context.Background(), &proto.CreateLVRequest{
diff --git a/lvmd/vgservice_test.go b/internal/lvmd/vgservice_test.go
similarity index 95%
rename from lvmd/vgservice_test.go
rename to internal/lvmd/vgservice_test.go
index 1a655851..718abbaf 100644
--- a/lvmd/vgservice_test.go
+++ b/internal/lvmd/vgservice_test.go
@@ -9,9 +9,10 @@ import (
 	"time"
 
 	"github.com/go-logr/logr/testr"
-	"github.com/topolvm/topolvm/lvmd/command"
-	"github.com/topolvm/topolvm/lvmd/proto"
-	"github.com/topolvm/topolvm/lvmd/testutils"
+	"github.com/topolvm/topolvm/internal/lvmd/command"
+	"github.com/topolvm/topolvm/internal/lvmd/testutils"
+	"github.com/topolvm/topolvm/pkg/lvmd/proto"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 	"google.golang.org/grpc/metadata"
 	ctrl "sigs.k8s.io/controller-runtime"
 )
@@ -56,21 +57,21 @@ func testWatch(t *testing.T) {
 	overprovisionRatio := float64(2.0)
 	tests := []struct {
 		name          string
-		deviceClasses []*DeviceClass
+		deviceClasses []*lvmdTypes.DeviceClass
 	}{
 
-		{"volumegroup", []*DeviceClass{
+		{"volumegroup", []*lvmdTypes.DeviceClass{
 			{
 				Name:        "dc",
 				VolumeGroup: "test_vgservice",
 			}},
 		},
-		{"thinpool", []*DeviceClass{
+		{"thinpool", []*lvmdTypes.DeviceClass{
 			{
 				Name:        "dc",
 				VolumeGroup: "test_vgservice",
-				Type:        TypeThin,
-				ThinPoolConfig: &ThinPoolConfig{
+				Type:        lvmdTypes.TypeThin,
+				ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 					Name:               "test_pool",
 					OverprovisionRatio: overprovisionRatio,
 				},
@@ -165,7 +166,7 @@ func testVGService(t *testing.T, vg *command.VolumeGroup) {
 	thindev := poolName
 	vgService, _ := NewVGService(
 		NewDeviceClassManager(
-			[]*DeviceClass{
+			[]*lvmdTypes.DeviceClass{
 				{
 					// volumegroup target
 					Name:        thickdev,
@@ -177,8 +178,8 @@ func testVGService(t *testing.T, vg *command.VolumeGroup) {
 					Name:        thindev,
 					VolumeGroup: vg.Name(),
 					SpareGB:     &spareGB,
-					Type:        TypeThin,
-					ThinPoolConfig: &ThinPoolConfig{
+					Type:        lvmdTypes.TypeThin,
+					ThinPoolConfig: &lvmdTypes.ThinPoolConfig{
 						Name:               poolName,
 						OverprovisionRatio: overprovisionRatio,
 					},
diff --git a/e2e/.dockerignore b/test/e2e/.dockerignore
similarity index 100%
rename from e2e/.dockerignore
rename to test/e2e/.dockerignore
diff --git a/e2e/.gitignore b/test/e2e/.gitignore
similarity index 100%
rename from e2e/.gitignore
rename to test/e2e/.gitignore
diff --git a/e2e/Dockerfile b/test/e2e/Dockerfile
similarity index 100%
rename from e2e/Dockerfile
rename to test/e2e/Dockerfile
diff --git a/e2e/Makefile b/test/e2e/Makefile
similarity index 93%
rename from e2e/Makefile
rename to test/e2e/Makefile
index 2309d5d3..29958da1 100644
--- a/e2e/Makefile
+++ b/test/e2e/Makefile
@@ -1,4 +1,4 @@
-include ../versions.mk
+include ../../versions.mk
 
 # parameters
 # none/daemonset/deployment
@@ -14,9 +14,9 @@ CLUSTER_NAME := topolvm-e2e
 CURL := curl -sSLf
 GINKGO := $(BINDIR)/ginkgo-$(GINKGO_VERSION)
 GINKGO_FLAGS :=
-GO_FILES := $(shell find .. -path ../e2e -prune -o -name '*.go' -print)
-HELM := ../bin/helm
-KIND := ../bin/kind
+GO_FILES := $(shell find ../.. -path ../../test -prune -o -name '*.go' -print)
+HELM := ../../bin/helm
+KIND := ../../bin/kind
 KIND_CONFIG := topolvm-cluster.yaml
 KUBECTL := $(BINDIR)/kubectl-$(KUBERNETES_VERSION)
 MINIKUBE_FEATURE_GATES="ReadWriteOncePod=true"
@@ -27,7 +27,7 @@ export MINIKUBE_HOME
 
 DOMAIN_NAME := topolvm.io
 HELM_VALUES_FILES := manifests/values/base.yaml
-SCHEDULER_CONFIG := ../deploy/scheduler-config/scheduler-config.yaml
+SCHEDULER_CONFIG := ../../deploy/scheduler-config/scheduler-config.yaml
 STORAGE_CAPACITY := true
 USE_LEGACY :=
 
@@ -42,7 +42,7 @@ endif
 ifeq ($(TEST_LEGACY),true)
 DOMAIN_NAME := topolvm.cybozu.com
 HELM_VALUES_FILES += manifests/values/legacy.yaml
-SCHEDULER_CONFIG := ../deploy/scheduler-config/scheduler-config-legacy.yaml
+SCHEDULER_CONFIG := ../../deploy/scheduler-config/scheduler-config-legacy.yaml
 USE_LEGACY := true
 endif
 
@@ -54,8 +54,8 @@ endif
 
 topolvm.img: $(GO_FILES)
 	mkdir -p tmpbin
-	CGO_ENABLED=0 go build -o tmpbin/hypertopolvm ../pkg/hypertopolvm
-	$(MAKE) -f ../csi-sidecars.mk OUTPUT_DIR=tmpbin
+	CGO_ENABLED=0 go build -o tmpbin/hypertopolvm ../../cmd/hypertopolvm
+	$(MAKE) -f ../../csi-sidecars.mk OUTPUT_DIR=tmpbin
 	docker build --no-cache --rm=false -f Dockerfile -t topolvm:dev .
 	docker save -o $@ topolvm:dev
 
@@ -87,7 +87,7 @@ shutdown-kind: $(KIND)
 .PHONY: start-lvmd
 start-lvmd:
 	mkdir -p build $(BACKING_STORE)
-	go build -o build/lvmd ../pkg/lvmd
+	go build -o build/lvmd ../../cmd/lvmd
 	if [ $$(ls -1 $(BACKING_STORE)/backing_store* 2>/dev/null | wc -l) -ne 0 ]; then $(MAKE) stop-lvmd; fi
 	for i in $$(seq 3); do \
 		mkdir -p /tmp/topolvm/worker$$i; \
@@ -140,10 +140,10 @@ $(GINKGO): | $(BINDIR)
 	mv $(BINDIR)/ginkgo $@
 
 $(HELM):
-	$(MAKE) -C .. install-helm
+	$(MAKE) -C ../.. install-helm
 
 $(KIND):
-	$(MAKE) -C .. install-kind
+	$(MAKE) -C ../.. install-kind
 
 $(KUBECTL): | $(BINDIR)
 	$(CURL) -o $@ https://storage.googleapis.com/kubernetes-release/release/v$(KUBERNETES_VERSION)/bin/linux/amd64/kubectl
@@ -263,8 +263,8 @@ common/setup-components: $(HELM) $(KUBECTL)
 	$(KUBECTL) label namespace kube-system $(DOMAIN_NAME)/webhook=ignore
 	$(HELM) repo add jetstack https://charts.jetstack.io
 	$(HELM) repo update
-	$(HELM) dependency build ../charts/topolvm/
-	$(HELM) install --namespace=topolvm-system topolvm ../charts/topolvm/ $(patsubst %,-f %,$(HELM_VALUES_FILES))
+	$(HELM) dependency build ../../charts/topolvm/
+	$(HELM) install --namespace=topolvm-system topolvm ../../charts/topolvm/ $(patsubst %,-f %,$(HELM_VALUES_FILES))
 	$(KUBECTL) wait --for=condition=available --timeout=120s -n topolvm-system deployments/topolvm-controller
 	$(KUBECTL) wait --for=condition=ready --timeout=120s -n topolvm-system -l="app.kubernetes.io/component=controller,app.kubernetes.io/name=topolvm" pod
 	$(KUBECTL) wait --for=condition=ready --timeout=120s -n topolvm-system certificate/topolvm-mutatingwebhook
diff --git a/e2e/README.md b/test/e2e/README.md
similarity index 100%
rename from e2e/README.md
rename to test/e2e/README.md
diff --git a/e2e/clone_test.go b/test/e2e/clone_test.go
similarity index 100%
rename from e2e/clone_test.go
rename to test/e2e/clone_test.go
diff --git a/e2e/e2e_test.go b/test/e2e/e2e_test.go
similarity index 100%
rename from e2e/e2e_test.go
rename to test/e2e/e2e_test.go
diff --git a/e2e/helper_test.go b/test/e2e/helper_test.go
similarity index 100%
rename from e2e/helper_test.go
rename to test/e2e/helper_test.go
diff --git a/e2e/logical_volume_test.go b/test/e2e/logical_volume_test.go
similarity index 99%
rename from e2e/logical_volume_test.go
rename to test/e2e/logical_volume_test.go
index 39f678ab..e19d6a35 100644
--- a/e2e/logical_volume_test.go
+++ b/test/e2e/logical_volume_test.go
@@ -10,7 +10,7 @@ import (
 	. "github.com/onsi/gomega"
 	topolvmlegacyv1 "github.com/topolvm/topolvm/api/legacy/v1"
 	topolvmv1 "github.com/topolvm/topolvm/api/v1"
-	clientwrapper "github.com/topolvm/topolvm/client"
+	clientwrapper "github.com/topolvm/topolvm/internal/client"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime"
diff --git a/e2e/lvcreate_options_test.go b/test/e2e/lvcreate_options_test.go
similarity index 100%
rename from e2e/lvcreate_options_test.go
rename to test/e2e/lvcreate_options_test.go
diff --git a/e2e/lvmd1.yaml b/test/e2e/lvmd1.yaml
similarity index 100%
rename from e2e/lvmd1.yaml
rename to test/e2e/lvmd1.yaml
diff --git a/e2e/lvmd2.yaml b/test/e2e/lvmd2.yaml
similarity index 100%
rename from e2e/lvmd2.yaml
rename to test/e2e/lvmd2.yaml
diff --git a/e2e/lvmd3.yaml b/test/e2e/lvmd3.yaml
similarity index 100%
rename from e2e/lvmd3.yaml
rename to test/e2e/lvmd3.yaml
diff --git a/e2e/manifests/values/base.yaml b/test/e2e/manifests/values/base.yaml
similarity index 100%
rename from e2e/manifests/values/base.yaml
rename to test/e2e/manifests/values/base.yaml
diff --git a/e2e/manifests/values/daemonset-scheduler.yaml b/test/e2e/manifests/values/daemonset-scheduler.yaml
similarity index 100%
rename from e2e/manifests/values/daemonset-scheduler.yaml
rename to test/e2e/manifests/values/daemonset-scheduler.yaml
diff --git a/e2e/manifests/values/deployment-scheduler.yaml b/test/e2e/manifests/values/deployment-scheduler.yaml
similarity index 100%
rename from e2e/manifests/values/deployment-scheduler.yaml
rename to test/e2e/manifests/values/deployment-scheduler.yaml
diff --git a/e2e/manifests/values/embedded-lvmd.yaml b/test/e2e/manifests/values/embedded-lvmd.yaml
similarity index 100%
rename from e2e/manifests/values/embedded-lvmd.yaml
rename to test/e2e/manifests/values/embedded-lvmd.yaml
diff --git a/e2e/manifests/values/legacy.yaml b/test/e2e/manifests/values/legacy.yaml
similarity index 100%
rename from e2e/manifests/values/legacy.yaml
rename to test/e2e/manifests/values/legacy.yaml
diff --git a/e2e/manifests/values/systemd-service-lvmd.yaml b/test/e2e/manifests/values/systemd-service-lvmd.yaml
similarity index 100%
rename from e2e/manifests/values/systemd-service-lvmd.yaml
rename to test/e2e/manifests/values/systemd-service-lvmd.yaml
diff --git a/e2e/manifests/volumesnapshotclass_tpl.yaml b/test/e2e/manifests/volumesnapshotclass_tpl.yaml
similarity index 100%
rename from e2e/manifests/volumesnapshotclass_tpl.yaml
rename to test/e2e/manifests/volumesnapshotclass_tpl.yaml
diff --git a/e2e/metrics_test.go b/test/e2e/metrics_test.go
similarity index 93%
rename from e2e/metrics_test.go
rename to test/e2e/metrics_test.go
index 264e6a80..89026a4f 100644
--- a/e2e/metrics_test.go
+++ b/test/e2e/metrics_test.go
@@ -14,8 +14,9 @@ import (
 	. "github.com/onsi/gomega"
 	dto "github.com/prometheus/client_model/go"
 	"github.com/prometheus/common/expfmt"
-	"github.com/topolvm/topolvm/lvmd"
-	"github.com/topolvm/topolvm/pkg/lvmd/cmd"
+	lvmdApp "github.com/topolvm/topolvm/cmd/lvmd/app"
+	"github.com/topolvm/topolvm/internal/lvmd"
+	lvmdTypes "github.com/topolvm/topolvm/pkg/lvmd/types"
 	corev1 "k8s.io/api/core/v1"
 	"sigs.k8s.io/yaml"
 )
@@ -181,7 +182,7 @@ OUTER:
 	return true
 }
 
-func loadDeviceClasses(node string) ([]*lvmd.DeviceClass, error) {
+func loadDeviceClasses(node string) ([]*lvmdTypes.DeviceClass, error) {
 	var data []byte
 
 	var cm corev1.ConfigMap
@@ -206,7 +207,7 @@ func loadDeviceClasses(node string) ([]*lvmd.DeviceClass, error) {
 		}
 	}
 
-	var config cmd.Config
+	var config lvmdApp.Config
 	err = yaml.Unmarshal(data, &config)
 	if err != nil {
 		return nil, err
@@ -214,7 +215,7 @@ func loadDeviceClasses(node string) ([]*lvmd.DeviceClass, error) {
 	return config.DeviceClasses, nil
 }
 
-func vgFreeByte(deviceClass *lvmd.DeviceClass) (int64, error) {
+func vgFreeByte(deviceClass *lvmdTypes.DeviceClass) (int64, error) {
 	output, err := execAtLocal("sudo", nil, "vgs",
 		"-o", "vg_free",
 		"--noheadings",
@@ -232,11 +233,11 @@ func vgFreeByte(deviceClass *lvmd.DeviceClass) (int64, error) {
 	}
 
 	// FIXME? the current implementation does not subtract spare-gb if the type is thin.
-	if deviceClass.Type == lvmd.TypeThin {
+	if deviceClass.Type == lvmdTypes.TypeThin {
 		return int64(free), nil
 	}
 
-	spare := int(deviceClass.GetSpare())
+	spare := int(lvmd.GetSpare(deviceClass))
 	if free < spare {
 		free = 0
 	} else {
diff --git a/e2e/mount_option_test.go b/test/e2e/mount_option_test.go
similarity index 100%
rename from e2e/mount_option_test.go
rename to test/e2e/mount_option_test.go
diff --git a/e2e/multiple_vg_test.go b/test/e2e/multiple_vg_test.go
similarity index 100%
rename from e2e/multiple_vg_test.go
rename to test/e2e/multiple_vg_test.go
diff --git a/e2e/node_delete_test.go b/test/e2e/node_delete_test.go
similarity index 100%
rename from e2e/node_delete_test.go
rename to test/e2e/node_delete_test.go
diff --git a/e2e/read_write_once_pod_test.go b/test/e2e/read_write_once_pod_test.go
similarity index 100%
rename from e2e/read_write_once_pod_test.go
rename to test/e2e/read_write_once_pod_test.go
diff --git a/e2e/sanity_test.go b/test/e2e/sanity_test.go
similarity index 100%
rename from e2e/sanity_test.go
rename to test/e2e/sanity_test.go
diff --git a/e2e/scheduling_test.go b/test/e2e/scheduling_test.go
similarity index 100%
rename from e2e/scheduling_test.go
rename to test/e2e/scheduling_test.go
diff --git a/e2e/snapshot_test.go b/test/e2e/snapshot_test.go
similarity index 100%
rename from e2e/snapshot_test.go
rename to test/e2e/snapshot_test.go
diff --git a/e2e/suite_test.go b/test/e2e/suite_test.go
similarity index 99%
rename from e2e/suite_test.go
rename to test/e2e/suite_test.go
index d364317d..42d5c723 100644
--- a/e2e/suite_test.go
+++ b/test/e2e/suite_test.go
@@ -24,7 +24,7 @@ var nonControlPlaneNodeCount int
 
 func TestMtest(t *testing.T) {
 	if os.Getenv("E2ETEST") == "" {
-		t.Skip("Run under e2e/")
+		t.Skip("Run under test/e2e/")
 	}
 
 	RegisterFailHandler(Fail)
diff --git a/e2e/testdata/cloning/clone-pod-template.yaml b/test/e2e/testdata/cloning/clone-pod-template.yaml
similarity index 100%
rename from e2e/testdata/cloning/clone-pod-template.yaml
rename to test/e2e/testdata/cloning/clone-pod-template.yaml
diff --git a/e2e/testdata/cloning/clone-pvc-template.yaml b/test/e2e/testdata/cloning/clone-pvc-template.yaml
similarity index 100%
rename from e2e/testdata/cloning/clone-pvc-template.yaml
rename to test/e2e/testdata/cloning/clone-pvc-template.yaml
diff --git a/e2e/testdata/e2e/generic-ephemeral-volume.yaml b/test/e2e/testdata/e2e/generic-ephemeral-volume.yaml
similarity index 100%
rename from e2e/testdata/e2e/generic-ephemeral-volume.yaml
rename to test/e2e/testdata/e2e/generic-ephemeral-volume.yaml
diff --git a/e2e/testdata/e2e/node-capacity-pvc.yaml b/test/e2e/testdata/e2e/node-capacity-pvc.yaml
similarity index 100%
rename from e2e/testdata/e2e/node-capacity-pvc.yaml
rename to test/e2e/testdata/e2e/node-capacity-pvc.yaml
diff --git a/e2e/testdata/e2e/node-capacity-pvc2.yaml b/test/e2e/testdata/e2e/node-capacity-pvc2.yaml
similarity index 100%
rename from e2e/testdata/e2e/node-capacity-pvc2.yaml
rename to test/e2e/testdata/e2e/node-capacity-pvc2.yaml
diff --git a/e2e/testdata/e2e/pod-volume-device-template.yaml b/test/e2e/testdata/e2e/pod-volume-device-template.yaml
similarity index 100%
rename from e2e/testdata/e2e/pod-volume-device-template.yaml
rename to test/e2e/testdata/e2e/pod-volume-device-template.yaml
diff --git a/e2e/testdata/e2e/pod-volume-mount-template.yaml b/test/e2e/testdata/e2e/pod-volume-mount-template.yaml
similarity index 100%
rename from e2e/testdata/e2e/pod-volume-mount-template.yaml
rename to test/e2e/testdata/e2e/pod-volume-mount-template.yaml
diff --git a/e2e/testdata/e2e/pvc-template.yaml b/test/e2e/testdata/e2e/pvc-template.yaml
similarity index 100%
rename from e2e/testdata/e2e/pvc-template.yaml
rename to test/e2e/testdata/e2e/pvc-template.yaml
diff --git a/e2e/testdata/logical_volume/pvc-template.yaml b/test/e2e/testdata/logical_volume/pvc-template.yaml
similarity index 100%
rename from e2e/testdata/logical_volume/pvc-template.yaml
rename to test/e2e/testdata/logical_volume/pvc-template.yaml
diff --git a/e2e/testdata/metrics/pause-pod-with-pvc-template.yaml b/test/e2e/testdata/metrics/pause-pod-with-pvc-template.yaml
similarity index 100%
rename from e2e/testdata/metrics/pause-pod-with-pvc-template.yaml
rename to test/e2e/testdata/metrics/pause-pod-with-pvc-template.yaml
diff --git a/e2e/testdata/mount_option/pod-with-mount-option-pvc.yaml b/test/e2e/testdata/mount_option/pod-with-mount-option-pvc.yaml
similarity index 100%
rename from e2e/testdata/mount_option/pod-with-mount-option-pvc.yaml
rename to test/e2e/testdata/mount_option/pod-with-mount-option-pvc.yaml
diff --git a/e2e/testdata/multiple_vg/pod-pvc-template.yaml b/test/e2e/testdata/multiple_vg/pod-pvc-template.yaml
similarity index 100%
rename from e2e/testdata/multiple_vg/pod-pvc-template.yaml
rename to test/e2e/testdata/multiple_vg/pod-pvc-template.yaml
diff --git a/e2e/testdata/node_delete/statefulset-template.yaml b/test/e2e/testdata/node_delete/statefulset-template.yaml
similarity index 100%
rename from e2e/testdata/node_delete/statefulset-template.yaml
rename to test/e2e/testdata/node_delete/statefulset-template.yaml
diff --git a/e2e/testdata/pause-pod.yaml b/test/e2e/testdata/pause-pod.yaml
similarity index 100%
rename from e2e/testdata/pause-pod.yaml
rename to test/e2e/testdata/pause-pod.yaml
diff --git a/e2e/testdata/read_write_once_pod/pod-for-read-write-once-pod-template.yaml b/test/e2e/testdata/read_write_once_pod/pod-for-read-write-once-pod-template.yaml
similarity index 100%
rename from e2e/testdata/read_write_once_pod/pod-for-read-write-once-pod-template.yaml
rename to test/e2e/testdata/read_write_once_pod/pod-for-read-write-once-pod-template.yaml
diff --git a/e2e/testdata/read_write_once_pod/pvc-for-read-write-once-pod-template.yaml b/test/e2e/testdata/read_write_once_pod/pvc-for-read-write-once-pod-template.yaml
similarity index 100%
rename from e2e/testdata/read_write_once_pod/pvc-for-read-write-once-pod-template.yaml
rename to test/e2e/testdata/read_write_once_pod/pvc-for-read-write-once-pod-template.yaml
diff --git a/e2e/testdata/scheduling/pvc-pod-template.yaml b/test/e2e/testdata/scheduling/pvc-pod-template.yaml
similarity index 100%
rename from e2e/testdata/scheduling/pvc-pod-template.yaml
rename to test/e2e/testdata/scheduling/pvc-pod-template.yaml
diff --git a/e2e/testdata/snapshot_restore/restore-pod-template.yaml b/test/e2e/testdata/snapshot_restore/restore-pod-template.yaml
similarity index 100%
rename from e2e/testdata/snapshot_restore/restore-pod-template.yaml
rename to test/e2e/testdata/snapshot_restore/restore-pod-template.yaml
diff --git a/e2e/testdata/snapshot_restore/restore-pvc-template.yaml b/test/e2e/testdata/snapshot_restore/restore-pvc-template.yaml
similarity index 100%
rename from e2e/testdata/snapshot_restore/restore-pvc-template.yaml
rename to test/e2e/testdata/snapshot_restore/restore-pvc-template.yaml
diff --git a/e2e/testdata/snapshot_restore/snapshot-template.yaml b/test/e2e/testdata/snapshot_restore/snapshot-template.yaml
similarity index 100%
rename from e2e/testdata/snapshot_restore/snapshot-template.yaml
rename to test/e2e/testdata/snapshot_restore/snapshot-template.yaml
diff --git a/e2e/testdata/thin_provisioning/pod-template.yaml b/test/e2e/testdata/thin_provisioning/pod-template.yaml
similarity index 100%
rename from e2e/testdata/thin_provisioning/pod-template.yaml
rename to test/e2e/testdata/thin_provisioning/pod-template.yaml
diff --git a/e2e/testdata/thin_provisioning/pvc-template.yaml b/test/e2e/testdata/thin_provisioning/pvc-template.yaml
similarity index 100%
rename from e2e/testdata/thin_provisioning/pvc-template.yaml
rename to test/e2e/testdata/thin_provisioning/pvc-template.yaml
diff --git a/e2e/thin_provisioning_test.go b/test/e2e/thin_provisioning_test.go
similarity index 100%
rename from e2e/thin_provisioning_test.go
rename to test/e2e/thin_provisioning_test.go
diff --git a/e2e/topolvm-cluster.yaml b/test/e2e/topolvm-cluster.yaml
similarity index 100%
rename from e2e/topolvm-cluster.yaml
rename to test/e2e/topolvm-cluster.yaml
diff --git a/util/testing/testing.go b/test/util/testing.go
similarity index 90%
rename from util/testing/testing.go
rename to test/util/testing.go
index 32c73a56..34e1259e 100644
--- a/util/testing/testing.go
+++ b/test/util/testing.go
@@ -1,4 +1,4 @@
-package testing
+package util
 
 import (
 	"os"