[lxc-devel] [lxd/master] Extract Daemon.httpClient into a standalone HTTPClient function
freeekanayaka on Github
lxc-bot at linuxcontainers.org
Wed Aug 16 22:46:22 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 832 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170816/f6a84b2f/attachment.bin>
-------------- next part --------------
From 1fe9822d360185d80244c513eebac8443a5aa93a Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanayaka at canonical.com>
Date: Wed, 16 Aug 2017 22:39:26 +0000
Subject: [PATCH] Extract Daemon.httpClient into a standalone HTTPClient
function
This branch moves the Daemon.httpClient method (which really depends
only on the Daemon.proxy attribute) into a standalone function. The
goal is to progressively streamline the Daemon structure and factor
out ancillary code, to eventually be able to improve unit-testability
of both Deamon itself and its main consumer, the api*.go files.
While at it, the util.go file has also been moved to the util/
package, and split into two (encoding.go, and kernel.go).
Signed-off-by: Free Ekanayaka <free.ekanayaka at canonical.com>
---
lxd/api_1.0.go | 5 ++--
lxd/certificates.go | 5 ++--
lxd/container_instance_types.go | 3 +-
lxd/container_lxc.go | 5 ++--
lxd/container_patch.go | 3 +-
lxd/container_put.go | 3 +-
lxd/daemon.go | 44 -----------------------------
lxd/daemon_images.go | 3 +-
lxd/devlxd.go | 3 +-
lxd/images.go | 11 ++++----
lxd/networks.go | 5 ++--
lxd/profiles.go | 5 ++--
lxd/response.go | 7 +++--
lxd/storage_pools.go | 5 ++--
lxd/storage_volumes.go | 5 ++--
lxd/storage_zfs.go | 3 +-
lxd/{util.go => util/encoding.go} | 19 ++++---------
lxd/util/http.go | 58 +++++++++++++++++++++++++++++++++++++++
lxd/util/kernel.go | 18 ++++++++++++
19 files changed, 124 insertions(+), 86 deletions(-)
rename lxd/{util.go => util/encoding.go} (64%)
create mode 100644 lxd/util/http.go
create mode 100644 lxd/util/kernel.go
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 58668a089..b29ccf148 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -11,6 +11,7 @@ import (
"gopkg.in/lxc/go-lxc.v2"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/osarch"
@@ -248,7 +249,7 @@ func api10Put(d *Daemon, r *http.Request) Response {
return SmartError(err)
}
- err = etagCheck(r, daemonConfigRender())
+ err = util.EtagCheck(r, daemonConfigRender())
if err != nil {
return PreconditionFailed(err)
}
@@ -267,7 +268,7 @@ func api10Patch(d *Daemon, r *http.Request) Response {
return SmartError(err)
}
- err = etagCheck(r, daemonConfigRender())
+ err = util.EtagCheck(r, daemonConfigRender())
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/certificates.go b/lxd/certificates.go
index 008c93c27..d15f0fb53 100644
--- a/lxd/certificates.go
+++ b/lxd/certificates.go
@@ -12,6 +12,7 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
@@ -193,7 +194,7 @@ func certificateFingerprintPut(d *Daemon, r *http.Request) Response {
}
fingerprint = oldEntry.Fingerprint
- err = etagCheck(r, oldEntry)
+ err = util.EtagCheck(r, oldEntry)
if err != nil {
return PreconditionFailed(err)
}
@@ -215,7 +216,7 @@ func certificateFingerprintPatch(d *Daemon, r *http.Request) Response {
}
fingerprint = oldEntry.Fingerprint
- err = etagCheck(r, oldEntry)
+ err = util.EtagCheck(r, oldEntry)
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/container_instance_types.go b/lxd/container_instance_types.go
index 77259e3bf..c5225b7f8 100644
--- a/lxd/container_instance_types.go
+++ b/lxd/container_instance_types.go
@@ -9,6 +9,7 @@ import (
"gopkg.in/yaml.v2"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/logger"
"github.com/lxc/lxd/shared/version"
@@ -67,7 +68,7 @@ func instanceRefreshTypes(d *Daemon) error {
downloadParse := func(filename string, target interface{}) error {
url := fmt.Sprintf("https://images.linuxcontainers.org/meta/instance-types/%s", filename)
- httpClient, err := d.httpClient("")
+ httpClient, err := util.HTTPClient("", d.proxy)
if err != nil {
return err
}
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 6e21c0be5..edac0c2e3 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -26,6 +26,7 @@ import (
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/types"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
@@ -1627,7 +1628,7 @@ func (c *containerLXC) startCommon() (string, error) {
if kernelModules != "" {
for _, module := range strings.Split(kernelModules, ",") {
module = strings.TrimPrefix(module, " ")
- err := loadModule(module)
+ err := util.LoadModule(module)
if err != nil {
return "", fmt.Errorf("Failed to load kernel module '%s': %s", module, err)
}
@@ -3487,7 +3488,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
} else if key == "linux.kernel_modules" && value != "" {
for _, module := range strings.Split(value, ",") {
module = strings.TrimPrefix(module, " ")
- err := loadModule(module)
+ err := util.LoadModule(module)
if err != nil {
return fmt.Errorf("Failed to load kernel module '%s': %s", module, err)
}
diff --git a/lxd/container_patch.go b/lxd/container_patch.go
index 02fd3a0aa..3d042163d 100644
--- a/lxd/container_patch.go
+++ b/lxd/container_patch.go
@@ -10,6 +10,7 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/osarch"
@@ -25,7 +26,7 @@ func containerPatch(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{c.Architecture(), c.LocalConfig(), c.LocalDevices(), c.IsEphemeral(), c.Profiles()}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/container_put.go b/lxd/container_put.go
index 84bc7b99f..351cce765 100644
--- a/lxd/container_put.go
+++ b/lxd/container_put.go
@@ -9,6 +9,7 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/osarch"
@@ -28,7 +29,7 @@ func containerPut(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{c.Architecture(), c.LocalConfig(), c.LocalDevices(), c.IsEphemeral(), c.Profiles()}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 186985219..bc728d098 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -6,7 +6,6 @@ import (
"crypto/x509"
"database/sql"
"encoding/hex"
- "encoding/pem"
"fmt"
"io"
"io/ioutil"
@@ -107,49 +106,6 @@ type Command struct {
patch func(d *Daemon, r *http.Request) Response
}
-func (d *Daemon) httpClient(certificate string) (*http.Client, error) {
- var err error
- var cert *x509.Certificate
-
- if certificate != "" {
- certBlock, _ := pem.Decode([]byte(certificate))
- if certBlock == nil {
- return nil, fmt.Errorf("Invalid certificate")
- }
-
- cert, err = x509.ParseCertificate(certBlock.Bytes)
- if err != nil {
- return nil, err
- }
- }
-
- tlsConfig, err := shared.GetTLSConfig("", "", "", cert)
- if err != nil {
- return nil, err
- }
-
- tr := &http.Transport{
- TLSClientConfig: tlsConfig,
- Dial: shared.RFC3493Dialer,
- Proxy: d.proxy,
- DisableKeepAlives: true,
- }
-
- myhttp := http.Client{
- Transport: tr,
- }
-
- // Setup redirect policy
- myhttp.CheckRedirect = func(req *http.Request, via []*http.Request) error {
- // Replicate the headers
- req.Header = via[len(via)-1].Header
-
- return nil
- }
-
- return &myhttp, nil
-}
-
func readMyCert() (string, string, error) {
certf := shared.VarPath("server.crt")
keyf := shared.VarPath("server.key")
diff --git a/lxd/daemon_images.go b/lxd/daemon_images.go
index 659bb0d1a..145e45ed5 100644
--- a/lxd/daemon_images.go
+++ b/lxd/daemon_images.go
@@ -16,6 +16,7 @@ import (
"github.com/lxc/lxd/client"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/cancel"
@@ -423,7 +424,7 @@ func (d *Daemon) ImageDownload(op *operation, server string, protocol string, ce
}
} else if protocol == "direct" {
// Setup HTTP client
- httpClient, err := d.httpClient(certificate)
+ httpClient, err := util.HTTPClient(certificate, d.proxy)
if err != nil {
return nil, err
}
diff --git a/lxd/devlxd.go b/lxd/devlxd.go
index 5dd17b454..68f2ca518 100644
--- a/lxd/devlxd.go
+++ b/lxd/devlxd.go
@@ -16,6 +16,7 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/logger"
"github.com/lxc/lxd/shared/version"
@@ -119,7 +120,7 @@ func hoistReq(f func(container, *http.Request) *devLxdResponse, d *Daemon) func(
http.Error(w, fmt.Sprintf("%s", resp.content), resp.code)
} else if resp.ctype == "json" {
w.Header().Set("Content-Type", "application/json")
- WriteJSON(w, resp.content)
+ util.WriteJSON(w, resp.content, debug)
} else {
w.Header().Set("Content-Type", "application/octet-stream")
fmt.Fprintf(w, resp.content.(string))
diff --git a/lxd/images.go b/lxd/images.go
index ce016c2cc..c9dc99ae7 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -23,6 +23,7 @@ import (
"gopkg.in/yaml.v2"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
@@ -358,7 +359,7 @@ func imgPostURLInfo(d *Daemon, req api.ImagesPost, op *operation) (*api.Image, e
return nil, fmt.Errorf("Missing URL")
}
- myhttp, err := d.httpClient("")
+ myhttp, err := util.HTTPClient("", d.proxy)
if err != nil {
return nil, err
}
@@ -1207,7 +1208,7 @@ func imagePut(d *Daemon, r *http.Request) Response {
// Validate ETag
etag := []interface{}{info.Public, info.AutoUpdate, info.Properties}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
@@ -1235,7 +1236,7 @@ func imagePatch(d *Daemon, r *http.Request) Response {
// Validate ETag
etag := []interface{}{info.Public, info.AutoUpdate, info.Properties}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
@@ -1392,7 +1393,7 @@ func aliasPut(d *Daemon, r *http.Request) Response {
}
// Validate ETag
- err = etagCheck(r, alias)
+ err = util.EtagCheck(r, alias)
if err != nil {
return PreconditionFailed(err)
}
@@ -1428,7 +1429,7 @@ func aliasPatch(d *Daemon, r *http.Request) Response {
}
// Validate ETag
- err = etagCheck(r, alias)
+ err = util.EtagCheck(r, alias)
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/networks.go b/lxd/networks.go
index a567de196..6f81691b3 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -15,6 +15,7 @@ import (
log "gopkg.in/inconshreveable/log15.v2"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
@@ -305,7 +306,7 @@ func networkPut(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{dbInfo.Name, dbInfo.Managed, dbInfo.Type, dbInfo.Description, dbInfo.Config}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
@@ -330,7 +331,7 @@ func networkPatch(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{dbInfo.Name, dbInfo.Managed, dbInfo.Type, dbInfo.Description, dbInfo.Config}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/profiles.go b/lxd/profiles.go
index 9c94633fb..57e6641f9 100644
--- a/lxd/profiles.go
+++ b/lxd/profiles.go
@@ -12,6 +12,7 @@ import (
_ "github.com/mattn/go-sqlite3"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
@@ -165,7 +166,7 @@ func profilePut(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{profile.Config, profile.Description, profile.Devices}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
@@ -188,7 +189,7 @@ func profilePatch(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{profile.Config, profile.Description, profile.Devices}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/response.go b/lxd/response.go
index de821a655..41629738e 100644
--- a/lxd/response.go
+++ b/lxd/response.go
@@ -14,6 +14,7 @@ import (
"github.com/mattn/go-sqlite3"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
)
@@ -35,7 +36,7 @@ type syncResponse struct {
func (r *syncResponse) Render(w http.ResponseWriter) error {
// Set an appropriate ETag header
if r.etag != nil {
- etag, err := etagHash(r.etag)
+ etag, err := util.EtagHash(r.etag)
if err == nil {
w.Header().Set("ETag", etag)
}
@@ -66,7 +67,7 @@ func (r *syncResponse) Render(w http.ResponseWriter) error {
Metadata: r.metadata,
}
- return WriteJSON(w, resp)
+ return util.WriteJSON(w, resp, debug)
}
func (r *syncResponse) String() string {
@@ -237,7 +238,7 @@ func (r *operationResponse) Render(w http.ResponseWriter) error {
w.Header().Set("Location", url)
w.WriteHeader(202)
- return WriteJSON(w, body)
+ return util.WriteJSON(w, body, debug)
}
func (r *operationResponse) String() string {
diff --git a/lxd/storage_pools.go b/lxd/storage_pools.go
index 6a89f3ebb..a616566a5 100644
--- a/lxd/storage_pools.go
+++ b/lxd/storage_pools.go
@@ -9,6 +9,7 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/version"
)
@@ -123,7 +124,7 @@ func storagePoolPut(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{dbInfo.Name, dbInfo.Driver, dbInfo.Config}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
@@ -161,7 +162,7 @@ func storagePoolPatch(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{dbInfo.Name, dbInfo.Driver, dbInfo.Config}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index 22c1f6497..556b3450e 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -8,6 +8,7 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/version"
@@ -261,7 +262,7 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{volume.Name, volume.Type, volume.Config}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
@@ -323,7 +324,7 @@ func storagePoolVolumeTypePatch(d *Daemon, r *http.Request) Response {
// Validate the ETag
etag := []interface{}{volume.Name, volume.Type, volume.Config}
- err = etagCheck(r, etag)
+ err = util.EtagCheck(r, etag)
if err != nil {
return PreconditionFailed(err)
}
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 2177282a1..0ebcc81a7 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -14,6 +14,7 @@ import (
"github.com/gorilla/websocket"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
@@ -46,7 +47,7 @@ func (s *storageZfs) StorageCoreInit() error {
}
s.sTypeName = typeName
- loadModule("zfs")
+ util.LoadModule("zfs")
if !zfsIsEnabled() {
return fmt.Errorf("the \"zfs\" tool is not enabled")
diff --git a/lxd/util.go b/lxd/util/encoding.go
similarity index 64%
rename from lxd/util.go
rename to lxd/util/encoding.go
index e85a5a849..71596ba0c 100644
--- a/lxd/util.go
+++ b/lxd/util/encoding.go
@@ -1,4 +1,4 @@
-package main
+package util
import (
"bytes"
@@ -11,7 +11,7 @@ import (
"github.com/lxc/lxd/shared"
)
-func WriteJSON(w http.ResponseWriter, body interface{}) error {
+func WriteJSON(w http.ResponseWriter, body interface{}, debug bool) error {
var output io.Writer
var captured *bytes.Buffer
@@ -30,7 +30,7 @@ func WriteJSON(w http.ResponseWriter, body interface{}) error {
return err
}
-func etagHash(data interface{}) (string, error) {
+func EtagHash(data interface{}) (string, error) {
etag := sha256.New()
err := json.NewEncoder(etag).Encode(data)
if err != nil {
@@ -40,13 +40,13 @@ func etagHash(data interface{}) (string, error) {
return fmt.Sprintf("%x", etag.Sum(nil)), nil
}
-func etagCheck(r *http.Request, data interface{}) error {
+func EtagCheck(r *http.Request, data interface{}) error {
match := r.Header.Get("If-Match")
if match == "" {
return nil
}
- hash, err := etagHash(data)
+ hash, err := EtagHash(data)
if err != nil {
return err
}
@@ -57,12 +57,3 @@ func etagCheck(r *http.Request, data interface{}) error {
return nil
}
-
-func loadModule(module string) error {
- if shared.PathExists(fmt.Sprintf("/sys/module/%s", module)) {
- return nil
- }
-
- _, err := shared.RunCommand("modprobe", module)
- return err
-}
diff --git a/lxd/util/http.go b/lxd/util/http.go
new file mode 100644
index 000000000..5f3eff9ff
--- /dev/null
+++ b/lxd/util/http.go
@@ -0,0 +1,58 @@
+package util
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "net/http"
+ "net/url"
+
+ "github.com/lxc/lxd/shared"
+)
+
+// HTTPClient returns an http.Client using the given certificate and proxy.
+func HTTPClient(certificate string, proxy proxyFunc) (*http.Client, error) {
+ var err error
+ var cert *x509.Certificate
+
+ if certificate != "" {
+ certBlock, _ := pem.Decode([]byte(certificate))
+ if certBlock == nil {
+ return nil, fmt.Errorf("Invalid certificate")
+ }
+
+ cert, err = x509.ParseCertificate(certBlock.Bytes)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ tlsConfig, err := shared.GetTLSConfig("", "", "", cert)
+ if err != nil {
+ return nil, err
+ }
+
+ tr := &http.Transport{
+ TLSClientConfig: tlsConfig,
+ Dial: shared.RFC3493Dialer,
+ Proxy: proxy,
+ DisableKeepAlives: true,
+ }
+
+ myhttp := http.Client{
+ Transport: tr,
+ }
+
+ // Setup redirect policy
+ myhttp.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+ // Replicate the headers
+ req.Header = via[len(via)-1].Header
+
+ return nil
+ }
+
+ return &myhttp, nil
+}
+
+// A function capable of proxing an HTTP request.
+type proxyFunc func(req *http.Request) (*url.URL, error)
diff --git a/lxd/util/kernel.go b/lxd/util/kernel.go
new file mode 100644
index 000000000..6f75915ba
--- /dev/null
+++ b/lxd/util/kernel.go
@@ -0,0 +1,18 @@
+package util
+
+import (
+ "fmt"
+
+ "github.com/lxc/lxd/shared"
+)
+
+// LoadModule loads the kernel module with the given name, by invoking
+// modprobe.
+func LoadModule(module string) error {
+ if shared.PathExists(fmt.Sprintf("/sys/module/%s", module)) {
+ return nil
+ }
+
+ _, err := shared.RunCommand("modprobe", module)
+ return err
+}
More information about the lxc-devel
mailing list