The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7544
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 481a238a5c3b79530e89c71b044914a6eb41faeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 17 Jun 2020 11:58:42 -0400 Subject: [PATCH 1/6] lxd/resources: Fix golint warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/resources/memory.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lxd/resources/memory.go b/lxd/resources/memory.go index 4a6544a659..b948f39e3b 100644 --- a/lxd/resources/memory.go +++ b/lxd/resources/memory.go @@ -153,14 +153,13 @@ func getTotalMemory() uint64 { return 0 } - var count uint64 = 0 - entries, err := ioutil.ReadDir(sysDevicesSystemMemory) if err != nil { return 0 } // Count the number of blocks + var count uint64 for _, entry := range entries { // Only consider directories if !entry.IsDir() { From cafae2434c4f0b64463f7abb9494f561549f5328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 17 Jun 2020 12:06:29 -0400 Subject: [PATCH 2/6] doc/api-extensions: Fix escaping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- doc/api-extensions.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/api-extensions.md b/doc/api-extensions.md index ffe908dc68..4c3fbc1542 100644 --- a/doc/api-extensions.md +++ b/doc/api-extensions.md @@ -977,17 +977,17 @@ This adds a new `size` field to the output of `/1.0/instances/<name>/snapshots/< This adds a writable endpoint for cluster members, allowing the editing of their roles. ## container\_nic\_routed\_host\_address -This introduces the `ipv4.host_address` and `ipv6.host_address` NIC config keys that can be used to control the +This introduces the `ipv4.host\_address` and `ipv6.host\_address` NIC config keys that can be used to control the host-side veth interface's IP addresses. This can be useful when using multiple routed NICs at the same time and needing a predictable next-hop address to use. This also alters the behaviour of `ipv4.gateway` and `ipv6.gateway` NIC config keys. When they are set to "auto" -the container will have its default gateway set to the value of `ipv4.host_address` or `ipv6.host_address` respectively. +the container will have its default gateway set to the value of `ipv4.host\_address` or `ipv6.host\_address` respectively. The default values are: -`ipv4.host_address`: 169.254.0.1 -`ipv6.host_address`: fe80::1 +`ipv4.host\_address`: 169.254.0.1 +`ipv6.host\_address`: fe80::1 This is backward compatible with the previous default behaviour. @@ -1015,11 +1015,11 @@ This introduces two new fields in `/1.0`, `os` and `os\_version`. Those are taken from the os-release data on the system. ## container\_nic\_routed\_host\_table -This introduces the `ipv4.host_table` and `ipv6.host_table` NIC config keys that can be used to add static routes +This introduces the `ipv4.host\_table` and `ipv6.host\_table` NIC config keys that can be used to add static routes for the instance's IPs to a custom policy routing table by ID. ## container\_nic\_ipvlan\_host\_table -This introduces the `ipv4.host_table` and `ipv6.host_table` NIC config keys that can be used to add static routes +This introduces the `ipv4.host\_table` and `ipv6.host\_table` NIC config keys that can be used to add static routes for the instance's IPs to a custom policy routing table by ID. ## container\_nic\_ipvlan\_mode From fb3583c9b612ede7dd7d49cae5b472c6b8ce3a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 17 Jun 2020 12:08:18 -0400 Subject: [PATCH 3/6] api: resource_cpu_isolated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- doc/api-extensions.md | 4 ++++ shared/api/resource.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/doc/api-extensions.md b/doc/api-extensions.md index 4c3fbc1542..a5d7c6a655 100644 --- a/doc/api-extensions.md +++ b/doc/api-extensions.md @@ -1073,3 +1073,7 @@ Bridge: - Default VLAN - VLAN filtering - Upper devices + +## resources\_cpu\_isolated +Add an `Isolated` property on CPU threads to indicate if the thread is +physically `Online` but is configured not to accept tasks. diff --git a/shared/api/resource.go b/shared/api/resource.go index 2942972513..0a97eae196 100644 --- a/shared/api/resource.go +++ b/shared/api/resource.go @@ -74,6 +74,9 @@ type ResourcesCPUThread struct { NUMANode uint64 `json:"numa_node" yaml:"numa_node"` Thread uint64 `json:"thread" yaml:"thread"` Online bool `json:"online" yaml:"online"` + + // API extension: resource_cpu_isolated + Isolated bool `json:"isolated" yaml:"isolated"` } // ResourcesGPU represents the GPU resources available on the system From 3f4fe3d2e4024843c996a2cb20277e71626d6e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 17 Jun 2020 12:09:03 -0400 Subject: [PATCH 4/6] lxd/resources: Add Isolated property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/resources/cpu.go | 66 ++++++++++++++++++++++++++++++++++++++++++ lxd/resources/utils.go | 9 ++++++ shared/api/resource.go | 2 +- 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/lxd/resources/cpu.go b/lxd/resources/cpu.go index 148bddfba7..70536f29f6 100644 --- a/lxd/resources/cpu.go +++ b/lxd/resources/cpu.go @@ -18,6 +18,68 @@ import ( var sysDevicesCPU = "/sys/devices/system/cpu" +// GetCPUIsolated returns a slice of IDs corresponding to isolated threads. +func GetCPUIsolated() []int64 { + isolatedPath := filepath.Join(sysDevicesCPU, "isolated") + + isolatedCpusInt := []int64{} + if sysfsExists(isolatedPath) { + buf, err := ioutil.ReadFile(isolatedPath) + if err != nil { + return isolatedCpusInt + } + + // File might exist even though there are no isolated cpus. + isolatedCpus := strings.TrimSpace(string(buf)) + if isolatedCpus != "" { + isolatedCpusInt, err = ParseCpuset(isolatedCpus) + if err != nil { + return isolatedCpusInt + } + } + } + + return isolatedCpusInt +} + +// ParseCpuset parses a limits.cpu range into a list of CPU ids. +func ParseCpuset(cpu string) ([]int64, error) { + cpus := []int64{} + chunks := strings.Split(cpu, ",") + for _, chunk := range chunks { + if strings.Contains(chunk, "-") { + // Range + fields := strings.SplitN(chunk, "-", 2) + if len(fields) != 2 { + return nil, fmt.Errorf("Invalid cpuset value: %s", cpu) + } + + low, err := strconv.ParseInt(fields[0], 10, 64) + if err != nil { + return nil, fmt.Errorf("Invalid cpuset value: %s", cpu) + } + + high, err := strconv.ParseInt(fields[1], 10, 64) + if err != nil { + return nil, fmt.Errorf("Invalid cpuset value: %s", cpu) + } + + for i := low; i <= high; i++ { + cpus = append(cpus, i) + } + } else { + // Simple entry + nr, err := strconv.ParseInt(chunk, 10, 64) + if err != nil { + return nil, fmt.Errorf("Invalid cpuset value: %s", cpu) + } + cpus = append(cpus, nr) + } + } + + return cpus, nil +} + func getCPUCache(path string) ([]api.ResourcesCPUCache, error) { caches := []api.ResourcesCPUCache{} @@ -92,6 +154,9 @@ func getCPUCache(path string) ([]api.ResourcesCPUCache, error) { func GetCPU() (*api.ResourcesCPU, error) { cpu := api.ResourcesCPU{} + // Get the isolated CPUs + isolated := GetCPUIsolated() + // Temporary storage cpuSockets := map[uint64]*api.ResourcesCPUSocket{} cpuCores := map[uint64]map[string]*api.ResourcesCPUCore{} @@ -299,6 +364,7 @@ func GetCPU() (*api.ResourcesCPU, error) { } } thread.ID = threadNumber + thread.Isolated = int64InSlice(threadNumber, isolated) thread.Thread = uint64(len(resCore.Threads)) // NUMA node diff --git a/lxd/resources/utils.go b/lxd/resources/utils.go index 8290b5c6ab..e5335e03e0 100644 --- a/lxd/resources/utils.go +++ b/lxd/resources/utils.go @@ -47,6 +47,15 @@ func stringInSlice(key string, list []string) bool { return false } +func int64InSlice(key int64, list []int64) bool { + for _, entry := range list { + if entry == key { + return true + } + } + return false +} + func sysfsExists(path string) bool { _, err := os.Lstat(path) if err == nil { diff --git a/shared/api/resource.go b/shared/api/resource.go index 0a97eae196..4ccefc43eb 100644 --- a/shared/api/resource.go +++ b/shared/api/resource.go @@ -76,7 +76,7 @@ type ResourcesCPUThread struct { Online bool `json:"online" yaml:"online"` // API extension: resource_cpu_isolated - Isolated bool `json:"isolated" yaml:"isolated"` + Isolated bool `json:"isolated" yaml:"isolated"` } // ResourcesGPU represents the GPU resources available on the system From b448225849304e84fa2514893b5f50d295a5389a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 17 Jun 2020 12:21:01 -0400 Subject: [PATCH 5/6] lxd/resources: Don't use shared MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/resources/system.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lxd/resources/system.go b/lxd/resources/system.go index bf0a7f494d..a074b54888 100644 --- a/lxd/resources/system.go +++ b/lxd/resources/system.go @@ -9,7 +9,6 @@ import ( "github.com/pkg/errors" - "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/api" ) @@ -134,14 +133,19 @@ func systemGetType() string { return "unknown" } + runDetectVirt := func(flag string) error { + cmd := exec.Command("systemd-detect-virt", flag) + return cmd.Run() + } + // If this returns 0, we're in a container. - _, err = shared.RunCommand("systemd-detect-virt", "--container") + err = runDetectVirt("--container") if err == nil { return "container" } // If this returns 0, we're in a VM. - _, err = shared.RunCommand("systemd-detect-virt", "--vm") + err = runDetectVirt("--vm") if err == nil { return "virtual-machine" } From 64acf92527cc0a04c31ea3a4d17e89f47bd71ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 17 Jun 2020 12:41:51 -0400 Subject: [PATCH 6/6] lxd/devices: Use resources for cpuset parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/devices.go | 38 ++++++++--------------------- lxd/instance/drivers/driver_qemu.go | 2 +- lxd/instance/instance_utils.go | 37 ---------------------------- 3 files changed, 11 insertions(+), 66 deletions(-) diff --git a/lxd/devices.go b/lxd/devices.go index 3442765652..65aa81ec44 100644 --- a/lxd/devices.go +++ b/lxd/devices.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "io/ioutil" "os" "path" "path/filepath" @@ -16,6 +15,7 @@ import ( "github.com/lxc/lxd/lxd/device" "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" + "github.com/lxc/lxd/lxd/resources" "github.com/lxc/lxd/lxd/state" "github.com/lxc/lxd/shared" log "github.com/lxc/lxd/shared/log15" @@ -55,7 +55,7 @@ static int get_hidraw_devinfo(int fd, struct hidraw_devinfo *info) import "C" type deviceTaskCPU struct { - id int + id int64 strId string count *int } @@ -337,34 +337,16 @@ func deviceTaskBalance(s *state.State) { } } - effectiveCpusInt, err := instance.ParseCpuset(effectiveCpus) + effectiveCpusInt, err := resources.ParseCpuset(effectiveCpus) if err != nil { logger.Errorf("Error parsing effective CPU set") return } - isolatedCpusInt := []int{} - if shared.PathExists("/sys/devices/system/cpu/isolated") { - buf, err := ioutil.ReadFile("/sys/devices/system/cpu/isolated") - if err != nil { - logger.Errorf("Error reading host's isolated cpu") - return - } - - // File might exist even though there are no isolated cpus. - isolatedCpus := strings.TrimSpace(string(buf)) - if isolatedCpus != "" { - isolatedCpusInt, err = instance.ParseCpuset(isolatedCpus) - if err != nil { - logger.Errorf("Error parsing isolated CPU set: %s", string(isolatedCpus)) - return - } - } - } - + isolatedCpusInt := resources.GetCPUIsolated() effectiveCpusSlice := []string{} for _, id := range effectiveCpusInt { - if shared.IntInSlice(id, isolatedCpusInt) { + if shared.Int64InSlice(id, isolatedCpusInt) { continue } @@ -377,7 +359,7 @@ func deviceTaskBalance(s *state.State) { if err != nil && shared.PathExists("/sys/fs/cgroup/cpuset/lxc") { logger.Warn("Error setting lxd's cpuset.cpus", log.Ctx{"err": err}) } - cpus, err := instance.ParseCpuset(effectiveCpus) + cpus, err := resources.ParseCpuset(effectiveCpus) if err != nil { logger.Error("Error parsing host's cpu set", log.Ctx{"cpuset": effectiveCpus, "err": err}) return @@ -390,7 +372,7 @@ func deviceTaskBalance(s *state.State) { return } - fixedInstances := map[int][]instance.Instance{} + fixedInstances := map[int64][]instance.Instance{} balancedInstances := map[instance.Instance]int{} for _, c := range instances { conf := c.ExpandedConfig() @@ -410,12 +392,12 @@ func deviceTaskBalance(s *state.State) { balancedInstances[c] = count } else { // Pinned - containerCpus, err := instance.ParseCpuset(cpulimit) + containerCpus, err := resources.ParseCpuset(cpulimit) if err != nil { return } for _, nr := range containerCpus { - if !shared.IntInSlice(nr, cpus) { + if !shared.Int64InSlice(nr, cpus) { continue } @@ -431,7 +413,7 @@ func deviceTaskBalance(s *state.State) { // Balance things pinning := map[instance.Instance][]string{} - usage := map[int]deviceTaskCPU{} + usage := map[int64]deviceTaskCPU{} for _, id := range cpus { cpu := deviceTaskCPU{} diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go index dc7c9bbace..8316e05ab4 100644 --- a/lxd/instance/drivers/driver_qemu.go +++ b/lxd/instance/drivers/driver_qemu.go @@ -4458,7 +4458,7 @@ func (vm *qemu) cpuTopology(limit string) (int, int, int, map[uint64]uint64, map } // Expand the pins. - pins, err := instance.ParseCpuset(limit) + pins, err := resources.ParseCpuset(limit) if err != nil { return -1, -1, -1, nil, nil, err } diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go index 9bbb85f4ee..e9837df99b 100644 --- a/lxd/instance/instance_utils.go +++ b/lxd/instance/instance_utils.go @@ -874,40 +874,3 @@ func ValidName(instanceName string, isSnapshot bool) error { return nil } - -// ParseCpuset parses a limits.cpu range into a list of CPU ids. -func ParseCpuset(cpu string) ([]int, error) { - cpus := []int{} - chunks := strings.Split(cpu, ",") - for _, chunk := range chunks { - if strings.Contains(chunk, "-") { - // Range - fields := strings.SplitN(chunk, "-", 2) - if len(fields) != 2 { - return nil, fmt.Errorf("Invalid cpuset value: %s", cpu) - } - - low, err := strconv.Atoi(fields[0]) - if err != nil { - return nil, fmt.Errorf("Invalid cpuset value: %s", cpu) - } - - high, err := strconv.Atoi(fields[1]) - if err != nil { - return nil, fmt.Errorf("Invalid cpuset value: %s", cpu) - } - - for i := low; i <= high; i++ { - cpus = append(cpus, i) - } - } else { - // Simple entry - nr, err := strconv.Atoi(chunk) - if err != nil { - return nil, fmt.Errorf("Invalid cpuset value: %s", cpu) - } - cpus = append(cpus, nr) - } - } - return cpus, nil -}
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel