mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-03-13 10:26:06 +00:00
Including system metadata when posting to utility API
This commit is contained in:
committed by
Cuong Manh Le
parent
f859c52916
commit
6c02b161bf
@@ -69,14 +69,23 @@ func (u ErrorResponse) Error() string {
|
||||
}
|
||||
|
||||
type utilityRequest struct {
|
||||
UID string `json:"uid"`
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
UID string `json:"uid"`
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
}
|
||||
|
||||
// UtilityOrgRequest contains request data for calling Org API.
|
||||
type UtilityOrgRequest struct {
|
||||
ProvToken string `json:"prov_token"`
|
||||
Hostname string `json:"hostname"`
|
||||
ProvToken string `json:"prov_token"`
|
||||
Hostname string `json:"hostname"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
}
|
||||
|
||||
// ResolverConfigRequest contains request data for fetching resolver config.
|
||||
type ResolverConfigRequest struct {
|
||||
RawUID string
|
||||
Version string
|
||||
Metadata map[string]string
|
||||
}
|
||||
|
||||
// LogsRequest contains request data for sending runtime logs to API.
|
||||
@@ -85,26 +94,28 @@ type LogsRequest struct {
|
||||
Data io.ReadCloser `json:"-"`
|
||||
}
|
||||
|
||||
// FetchResolverConfig fetch Control D config for given uid.
|
||||
func FetchResolverConfig(ctx context.Context, rawUID, version string, cdDev bool) (*ResolverConfig, error) {
|
||||
// FetchResolverConfig fetch Control D config for a given request.
|
||||
func FetchResolverConfig(ctx context.Context, req *ResolverConfigRequest, cdDev bool) (*ResolverConfig, error) {
|
||||
logger := ctrld.LoggerFromCtx(ctx)
|
||||
ctrld.Log(ctx, logger.Debug(), "Fetching ControlD resolver configuration")
|
||||
|
||||
uid, clientID := ParseRawUID(rawUID)
|
||||
uid, clientID := ParseRawUID(req.RawUID)
|
||||
ctrld.Log(ctx, logger.Debug(), "Parsed UID: %s, ClientID: %s", uid, clientID)
|
||||
|
||||
req := utilityRequest{UID: uid}
|
||||
uReq := utilityRequest{
|
||||
UID: uid,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
if clientID != "" {
|
||||
req.ClientID = clientID
|
||||
uReq.ClientID = clientID
|
||||
ctrld.Log(ctx, logger.Debug(), "Including client ID in request")
|
||||
}
|
||||
body, _ := json.Marshal(req)
|
||||
|
||||
body, _ := json.Marshal(uReq)
|
||||
ctrld.Log(ctx, logger.Debug(), "Sending resolver config request to ControlD API")
|
||||
return postUtilityAPI(ctx, version, cdDev, false, bytes.NewReader(body))
|
||||
return postUtilityAPI(ctx, req.Version, cdDev, false, bytes.NewReader(body))
|
||||
}
|
||||
|
||||
// FetchResolverUID fetch resolver uid from provision token.
|
||||
// FetchResolverUID fetch resolver uid from a given request.
|
||||
func FetchResolverUID(ctx context.Context, req *UtilityOrgRequest, version string, cdDev bool) (*ResolverConfig, error) {
|
||||
logger := ctrld.LoggerFromCtx(ctx)
|
||||
ctrld.Log(ctx, logger.Debug(), "Fetching resolver UID from provision token")
|
||||
@@ -115,15 +126,16 @@ func FetchResolverUID(ctx context.Context, req *UtilityOrgRequest, version strin
|
||||
}
|
||||
|
||||
hostname := req.Hostname
|
||||
if hostname == "" {
|
||||
if req.Hostname == "" {
|
||||
hostname, _ = os.Hostname()
|
||||
ctrld.Log(ctx, logger.Debug(), "Using system hostname: %s", hostname)
|
||||
req.Hostname = hostname
|
||||
} else {
|
||||
ctrld.Log(ctx, logger.Debug(), "Using provided hostname: %s", hostname)
|
||||
}
|
||||
|
||||
ctrld.Log(ctx, logger.Debug(), "Sending UID request to ControlD API")
|
||||
body, _ := json.Marshal(UtilityOrgRequest{ProvToken: req.ProvToken, Hostname: hostname})
|
||||
body, _ := json.Marshal(req)
|
||||
return postUtilityAPI(ctx, version, cdDev, false, bytes.NewReader(body))
|
||||
}
|
||||
|
||||
@@ -135,7 +147,7 @@ func UpdateCustomLastFailed(ctx context.Context, rawUID, version string, cdDev,
|
||||
req.ClientID = clientID
|
||||
}
|
||||
body, _ := json.Marshal(req)
|
||||
return postUtilityAPI(ctx, version, cdDev, true, bytes.NewReader(body))
|
||||
return postUtilityAPI(ctx, version, cdDev, lastUpdatedFailed, bytes.NewReader(body))
|
||||
}
|
||||
|
||||
func postUtilityAPI(ctx context.Context, version string, cdDev, lastUpdatedFailed bool, body io.Reader) (*ResolverConfig, error) {
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
package controld
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/Control-D-Inc/ctrld"
|
||||
)
|
||||
|
||||
func TestFetchResolverConfig(t *testing.T) {
|
||||
@@ -20,11 +23,18 @@ func TestFetchResolverConfig(t *testing.T) {
|
||||
{"valid dev", "p2", true, false},
|
||||
{"invalid uid", "abcd1234", false, true},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got, err := FetchResolverConfig(tc.uid, "dev-test", tc.dev)
|
||||
req := &ResolverConfigRequest{
|
||||
RawUID: tc.uid,
|
||||
Version: "dev-test",
|
||||
Metadata: ctrld.SystemMetadata(ctx),
|
||||
}
|
||||
got, err := FetchResolverConfig(ctx, req, tc.dev)
|
||||
require.False(t, (err != nil) != tc.wantErr, err)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, got.DOH)
|
||||
|
||||
25
internal/system/chassis_darwin.go
Normal file
25
internal/system/chassis_darwin.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/brunogui0812/sysprofiler"
|
||||
)
|
||||
|
||||
// GetChassisInfo retrieves hardware information including machine model type and vendor from the system profiler.
|
||||
func GetChassisInfo() (*ChassisInfo, error) {
|
||||
hardwares, err := sysprofiler.Hardware()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get hardware info: %w", err)
|
||||
}
|
||||
if len(hardwares) == 0 {
|
||||
return nil, errors.New("no hardware info found")
|
||||
}
|
||||
hardware := hardwares[0]
|
||||
info := &ChassisInfo{
|
||||
Type: hardware.MachineModel,
|
||||
Vendor: "Apple Inc.",
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
18
internal/system/chassis_others.go
Normal file
18
internal/system/chassis_others.go
Normal file
@@ -0,0 +1,18 @@
|
||||
//go:build !darwin
|
||||
|
||||
package system
|
||||
|
||||
import "github.com/jaypipes/ghw"
|
||||
|
||||
// GetChassisInfo retrieves hardware information including machine model type and vendor from the system profiler.
|
||||
func GetChassisInfo() (*ChassisInfo, error) {
|
||||
chassis, err := ghw.Chassis()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info := &ChassisInfo{
|
||||
Type: chassis.TypeDescription,
|
||||
Vendor: chassis.Vendor,
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
7
internal/system/metadata.go
Normal file
7
internal/system/metadata.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package system
|
||||
|
||||
// ChassisInfo represents the structural framework of a device, specifying its type and manufacturer information.
|
||||
type ChassisInfo struct {
|
||||
Type string
|
||||
Vendor string
|
||||
}
|
||||
8
internal/system/metadata_others.go
Normal file
8
internal/system/metadata_others.go
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build !windows
|
||||
|
||||
package system
|
||||
|
||||
// GetActiveDirectoryDomain returns AD domain name of this computer.
|
||||
func GetActiveDirectoryDomain() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
74
internal/system/metadata_windows.go
Normal file
74
internal/system/metadata_windows.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/microsoft/wmi/pkg/base/host"
|
||||
hh "github.com/microsoft/wmi/pkg/hardware/host"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// GetActiveDirectoryDomain returns AD domain name of this computer.
|
||||
func GetActiveDirectoryDomain() (string, error) {
|
||||
log.SetOutput(io.Discard)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
|
||||
// 1) Check environment variable
|
||||
envDomain := os.Getenv("USERDNSDOMAIN")
|
||||
if envDomain != "" {
|
||||
return strings.TrimSpace(envDomain), nil
|
||||
}
|
||||
|
||||
// 2) Query WMI via the microsoft/wmi library
|
||||
whost := host.NewWmiLocalHost()
|
||||
cs, err := hh.GetComputerSystem(whost)
|
||||
if cs != nil {
|
||||
defer cs.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
pod, err := cs.GetPropertyPartOfDomain()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if pod {
|
||||
domainVal, err := cs.GetPropertyDomain()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get domain property: %w", err)
|
||||
}
|
||||
domainName := strings.TrimSpace(fmt.Sprintf("%v", domainVal))
|
||||
if domainName == "" {
|
||||
return "", errors.New("machine does not appear to have a domain set")
|
||||
}
|
||||
return domainName, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// DomainJoinedStatus returns the domain joined status of the current computer.
|
||||
//
|
||||
// NETSETUP_JOIN_STATUS constants from Microsoft Windows API
|
||||
// See: https://learn.microsoft.com/en-us/windows/win32/api/lmjoin/ne-lmjoin-netsetup_join_status
|
||||
//
|
||||
// NetSetupUnknownStatus uint32 = 0 // The status is unknown
|
||||
// NetSetupUnjoined uint32 = 1 // The computer is not joined to a domain or workgroup
|
||||
// NetSetupWorkgroupName uint32 = 2 // The computer is joined to a workgroup
|
||||
// NetSetupDomainName uint32 = 3 // The computer is joined to a domain
|
||||
func DomainJoinedStatus() (uint32, error) {
|
||||
var domain *uint16
|
||||
var status uint32
|
||||
|
||||
if err := windows.NetGetJoinInformation(nil, &domain, &status); err != nil {
|
||||
return 0, fmt.Errorf("failed to get domain join status: %w", err)
|
||||
}
|
||||
defer windows.NetApiBufferFree((*byte)(unsafe.Pointer(domain)))
|
||||
|
||||
return status, nil
|
||||
}
|
||||
Reference in New Issue
Block a user