func (s *SupermicroX) Ntp(cfg *cfgresources.Ntp) (err error) {
	var enable string
	if cfg.Server1 == "" {
		s.log.V(1).Info("NTP resource expects parameter: server1.",
			"step", "applyNtpParams",
			"model", s.HardwareType())
		return
	}
	if cfg.Timezone == "" {
		s.log.V(1).Info("NTP resource expects parameter: timezone.",
			"step", "applyNtpParams",
			"model", s.HardwareType())
		return
	}
	tzLocation, err := time.LoadLocation(cfg.Timezone)
	if err != nil {
		s.log.V(1).Info("NTP resource declared parameter timezone invalid.",
			"step", "applyNtpParams",
			"model", s.HardwareType(),
			"declaredTtimezone", cfg.Timezone,
			"error", internal.ErrStringOrEmpty(err))
		return
	}
	tzUtcOffset := timezoneToUtcOffset(tzLocation)
	if !cfg.Enable {
		s.log.V(1).Info("Ntp resource declared with enable: false.",
			"step", "applyNtpParams",
			"model", s.HardwareType())
		return
	}
	enable = "on"
	t := time.Now().In(tzLocation)
	ts := fmt.Sprintf("%s %d %d:%d:%d %s (%s)",
		t.Format("Fri Jun 01"),
		t.Year(),
		t.Hour(),
		t.Minute(),
		t.Second(),
		t.Format("GMT+0200"),
		tzLocation)
	configDateTime := ConfigDateTime{
		Op:                 "config_date_time",
		Timezone:           tzUtcOffset,
		DstEn:              false,  
		Enable:             enable,
		NtpServerPrimary:   cfg.Server1,
		NtpServerSecondary: cfg.Server2,
		Year:               t.Year(),
		Month:              int(t.Month()),
		Day:                int(t.Day()),
		Hour:               int(t.Hour()),
		Minute:             int(t.Minute()),
		Second:             int(t.Second()),
		TimeStamp:          ts,
	}
	endpoint := "op.cgi"
	form, _ := query.Values(configDateTime)
	statusCode, err := s.post(endpoint, &form, []byte{}, "")
	if err != nil || statusCode != 200 {
		msg := "POST request to set Syslog config returned error."
		s.log.V(1).Info(msg,
			"ip", s.ip,
			"model", s.HardwareType(),
			"endpoint", endpoint,
			"statusCode", statusCode,
			"step", helper.WhosCalling(),
			"error", internal.ErrStringOrEmpty(err))
		return errors.New(msg)
	}
	s.log.V(1).Info("NTP config parameters applied.",
		"ip", s.ip,
		"model", s.HardwareType())
	return err
}
Ntp applies NTP configuration params
Ntp implements the Configure interface.
package supermicrox
import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net"
	"net/url"
	"strings"
	"time"
	"github.com/bmc-toolbox/bmclib/cfgresources"
	"github.com/bmc-toolbox/bmclib/devices"
	"github.com/bmc-toolbox/bmclib/internal"
	"github.com/bmc-toolbox/bmclib/internal/helper"
	"github.com/google/go-querystring/query"
)
var _ devices.Configure = (*SupermicroX)(nil)
func (s *SupermicroX) Resources() []string {
	return []string{
		"user",
		"syslog",
		"network",
		"ntp",
		"ldap_group",
		"https_cert",
	}
}
func (s *SupermicroX) ApplyCfg(config *cfgresources.ResourcesConfig) (err error) {
	return err
}
func (s *SupermicroX) Power(cfg *cfgresources.Power) (err error) {
	return err
}
func (s *SupermicroX) SetLicense(cfg *cfgresources.License) (err error) {
	return err
}
func (s *SupermicroX) Bios(cfg *cfgresources.Bios) (err error) {
	return err
}
func timezoneToUtcOffset(location *time.Location) (offset int) {
	utcTime := time.Now().In(location)
	_, offset = utcTime.Zone()
	return offset
}
func (s *SupermicroX) isRoleValid(role string) bool {
	validRoles := []string{"admin", "user"}
	for _, v := range validRoles {
		if role == v {
			return true
		}
	}
	return false
}
func (s *SupermicroX) queryUserAccounts() (userAccounts map[int]string, err error) {
	userAccounts = make(map[int]string)
	ipmi, err := s.query("CONFIG_INFO.XML=(0,0)")
	if err != nil {
		s.log.V(1).Info("error querying user accounts", "error", internal.ErrStringOrEmpty(err))
		return userAccounts, err
	}
	for idx, account := range ipmi.ConfigInfo.UserAccounts {
		userAccounts[idx] = account.Name
	}
	return userAccounts, err
}
func (s *SupermicroX) User(users []*cfgresources.User) (err error) {
	currentUsers, err := s.queryUserAccounts()
	if err != nil {
		msg := "Unable to query current user accounts."
		s.log.V(1).Info(msg, "ip", s.ip, "model", s.HardwareType(), "step", helper.WhosCalling(), "error", internal.ErrStringOrEmpty(err))
		return errors.New(msg)
	}
	for _, user := range users {
		if user.Name == "" {
			msg := "User resource expects parameter: Name."
			s.log.V(1).Info(msg, "step", "applyUserParams")
			return errors.New(msg)
		}
		if user.Password == "" {
			msg := "User resource expects parameter: Password."
			s.log.V(1).Info(msg, "step", "applyUserParams", "username", user.Name)
			return errors.New(msg)
		}
		if !s.isRoleValid(user.Role) {
			msg := "User resource Role must be declared and a must be a valid role: 'admin' OR 'user'."
			s.log.V(1).Info(msg, "step", "applyUserParams", "username", user.Name)
			return errors.New(msg)
		}
		configUser := ConfigUser{
			Username:     user.Name,
			Password:     user.Password,
			NewPrivilege: 3,
			UserID:       1,
		}
		if user.Role == "admin" {
			configUser.NewPrivilege = 4
		}
		var userID int
		comparisonNum := 10
		for id, name := range currentUsers {
			if name == user.Name {
				userID = id
				break
			} else if name == "" {
				if id < comparisonNum {
					userID = id
					comparisonNum = id
				}
			}
		}
		if userID == 0 {
			return errors.New("no user slots available")
		}
		configUser.UserID = userID
		if !user.Enable {
			configUser.Username = ""
		}
		endpoint := "config_user.cgi"
		form, _ := query.Values(configUser)
		statusCode, err := s.post(endpoint, &form, []byte{}, "")
		if err != nil || statusCode != 200 {
			msg := "POST request to set User config returned error."
			s.log.V(1).Info(msg,
				"ip", s.ip,
				"model", s.HardwareType(),
				"endpoint", endpoint,
				"statusCode", statusCode,
				"step", helper.WhosCalling(),
				"error", internal.ErrStringOrEmpty(err))
			return errors.New(msg)
		}
		s.log.V(1).Info("User parameters applied.", "ip", s.ip, "model", s.HardwareType(), "user", user.Name)
	}
	return err
}
func (s *SupermicroX) Network(cfg *cfgresources.Network) (reset bool, err error) {
	sshPort := 22
	if cfg.SSHPort != 0 && cfg.SSHPort != sshPort {
		sshPort = cfg.SSHPort
	}
	configPort := ConfigPort{
		Op:                "config_port",
		HTTPPort:          80,
		HTTPSPort:         443,
		IkvmPort:          5900,
		VMPort:            623,
		SSHPort:           sshPort,
		WsmanPort:         5985,
		SnmpPort:          161,
		httpEnable:        true,
		httpsEnable:       true,
		IkvmEnable:        true,
		VMEnable:          true,
		SSHEnable:         cfg.SSHEnable,
		SnmpEnable:        false,
		WsmanEnable:       false,
		SslRedirectEnable: true,
	}
	endpoint := "op.cgi"
	form, _ := query.Values(configPort)
	statusCode, err := s.post(endpoint, &form, []byte{}, "")
	if err != nil || statusCode != 200 {
		msg := "POST request to set Port config returned error."
		s.log.V(1).Info(msg,
			"ip", s.ip,
			"model", s.HardwareType(),
			"endpoint", endpoint,
			"statusCode", statusCode,
			"step", helper.WhosCalling(),
			"error", internal.ErrStringOrEmpty(err))
		return reset, errors.New(msg)
	}
	s.log.V(1).Info("Network config parameters applied.", "ip", s.ip, "model", s.HardwareType())
	return reset, err
}