Skip to content

Commit

Permalink
all: add AIX provider
Browse files Browse the repository at this point in the history
Add a implementation with CGO for AIX.

Process information are retrieved by /proc folder or with libperfstat,
getprocs syscalls.
  • Loading branch information
Clément Chigot committed Mar 16, 2020
1 parent b719bc4 commit fcc5cac
Show file tree
Hide file tree
Showing 12 changed files with 920 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add AIX support [#77](https://github.com/elastic/go-sysinfo/pull/77)

### Changed

### Deprecated
Expand Down
74 changes: 74 additions & 0 deletions providers/aix/boottime_aix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package aix

import (
"encoding/binary"
"os"
"time"

"github.com/pkg/errors"
)

// utmp can't be used by "encoding/binary" if generated by cgo,
// some pads will be missing.
type utmp struct {
User [256]uint8
Id [14]uint8
Line [64]uint8
X_Pad1 int16
Pid int32
Type int16
X_Pad2 int16
Time int64
Termination int16
Exit int16
Host [256]uint8
X__dbl_word_pad int32
X__reservedA [2]int32
X__reservedV [6]int32
}

const (
BOOT_TIME = 2
)

// BootTime returns the time at which the machine was started, truncated to the nearest second
func BootTime() (time.Time, error) {
// Get boot time from /etc/utmp
file, err := os.Open("/etc/utmp")
if err != nil {
return time.Time{}, errors.Wrapf(err, "failed to get host uptime: cannot open /etc/utmp")
}

defer file.Close()

for {
var utmp utmp
if err := binary.Read(file, binary.BigEndian, &utmp); err != nil {
break
}

if utmp.Type == BOOT_TIME {
return time.Unix(utmp.Time, 0), nil
}
}

return time.Time{}, errors.Wrapf(err, "failed to get host uptime: no utmp record")

}
41 changes: 41 additions & 0 deletions providers/aix/defs_aix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

// +build ignore

package aix

/*
#include <sys/types.h>
#include <utmp.h>
#include <sys/procfs.h>
*/
import "C"

type prcred C.prcred_t

type pstatus C.pstatus_t
type pr_timestruc64 C.pr_timestruc64_t
type pr_sigset C.pr_sigset_t
type fltset C.fltset_t
type lwpstatus C.lwpstatus_t
type pr_siginfo64 C.pr_siginfo64_t
type pr_stack64 C.pr_stack64_t
type pr_sigaction64 C.struct_pr_sigaction64
type prgregset C.prgregset_t
type prfpregset C.prfpregset_t
type pfamily C.pfamily_t
20 changes: 20 additions & 0 deletions providers/aix/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

// Package darwin implements the HostProvider and ProcessProvider interfaces
// for providing information about MacOS.
package aix
206 changes: 206 additions & 0 deletions providers/aix/host_aix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package aix

/*
#cgo LDFLAGS: -L/usr/lib -lperfstat
#include <libperfstat.h>
#include <procinfo.h>
#include <sys/proc.h>
*/
import "C"

import (
"os"
"time"

"github.com/joeshaw/multierror"
"github.com/pkg/errors"

"github.com/elastic/go-sysinfo/internal/registry"
"github.com/elastic/go-sysinfo/providers/shared"
"github.com/elastic/go-sysinfo/types"
)

//go:generate sh -c "go tool cgo -godefs defs_aix.go | sed 's/*byte/uint64/g' > ztypes_aix_ppc64.go"
// As cgo will return some psinfo's fields with *byte, binary.Read will refuse this type.

func init() {
registry.Register(aixSystem{})
}

type aixSystem struct{}

func (s aixSystem) Host() (types.Host, error) {
return newHost()
}

type host struct {
info types.HostInfo
}

func Architecture() (string, error) {
return "ppc", nil
}

func (h *host) Info() types.HostInfo {
return h.info
}

func (h *host) CPUTime() (types.CPUTimes, error) {
clock := uint64(C.sysconf(C._SC_CLK_TCK))
tick2nsec := func(val uint64) uint64 {
return val * 1e9 / clock
}

cpudata := C.perfstat_cpu_total_t{}

if _, err := C.perfstat_cpu_total(nil, &cpudata, C.sizeof_perfstat_cpu_total_t, 1); err != nil {
return types.CPUTimes{}, errors.Wrapf(err, "error while callin perfstat_cpu_total")
}

return types.CPUTimes{
User: time.Duration(tick2nsec(uint64(cpudata.user))),
System: time.Duration(tick2nsec(uint64(cpudata.sys))),
Idle: time.Duration(tick2nsec(uint64(cpudata.idle))),
IOWait: time.Duration(tick2nsec(uint64(cpudata.wait))),
}, nil
}

func (h *host) Memory() (*types.HostMemoryInfo, error) {
var mem types.HostMemoryInfo

pagesize := uint64(os.Getpagesize())

meminfo := C.perfstat_memory_total_t{}
_, err := C.perfstat_memory_total(nil, &meminfo, C.sizeof_perfstat_memory_total_t, 1)
if err != nil {
return nil, errors.Wrap(err, "perfstat_memory_total failed")
}

mem.Total = uint64(meminfo.real_total) * pagesize
mem.Free = uint64(meminfo.real_free) * pagesize
mem.Used = uint64(meminfo.real_inuse) * pagesize

// There is no real equivalent to memory available in AIX.
mem.Available = mem.Free

mem.VirtualTotal = uint64(meminfo.virt_total) * pagesize
mem.VirtualFree = mem.Free + uint64(meminfo.pgsp_free)*pagesize
mem.VirtualUsed = mem.VirtualTotal - mem.VirtualFree

return &mem, nil
}

func newHost() (*host, error) {
h := &host{}
r := &reader{}
r.architecture(h)
r.bootTime(h)
r.hostname(h)
r.network(h)
r.kernelVersion(h)
r.os(h)
r.time(h)
r.uniqueID(h)
return h, r.Err()
}

type reader struct {
errs []error
}

func (r *reader) addErr(err error) bool {
if err != nil {
if errors.Cause(err) != types.ErrNotImplemented {
r.errs = append(r.errs, err)
}
return true
}
return false
}

func (r *reader) Err() error {
if len(r.errs) > 0 {
return &multierror.MultiError{Errors: r.errs}
}
return nil
}

func (r *reader) architecture(h *host) {
v, err := Architecture()
if r.addErr(err) {
return
}
h.info.Architecture = v
}

func (r *reader) bootTime(h *host) {
v, err := BootTime()
if r.addErr(err) {
return
}
h.info.BootTime = v
}

func (r *reader) hostname(h *host) {
v, err := os.Hostname()
if r.addErr(err) {
return
}
h.info.Hostname = v
}

func (r *reader) network(h *host) {
ips, macs, err := shared.Network()
if r.addErr(err) {
return
}
h.info.IPs = ips
h.info.MACs = macs
}

func (r *reader) kernelVersion(h *host) {
v, err := KernelVersion()
if r.addErr(err) {
return
}
h.info.KernelVersion = v
}

func (r *reader) os(h *host) {
v, err := OperatingSystem()
if r.addErr(err) {
return
}
h.info.OS = v
}

func (r *reader) time(h *host) {
h.info.Timezone, h.info.TimezoneOffsetSec = time.Now().Zone()
}

func (r *reader) uniqueID(h *host) {
v, err := MachineID()
if r.addErr(err) {
return
}
h.info.UniqueID = v
}
Loading

0 comments on commit fcc5cac

Please sign in to comment.