mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
- support relay address
- ssh util - baremetal tasks
This commit is contained in:
Generated
+2
@@ -1785,6 +1785,8 @@
|
||||
"github.com/vmware/govmomi/vim25/types",
|
||||
"go.etcd.io/etcd/clientv3",
|
||||
"golang.org/x/crypto/ssh",
|
||||
"golang.org/x/net/bpf",
|
||||
"golang.org/x/net/ipv4",
|
||||
"gopkg.in/gin-gonic/gin.v1",
|
||||
"k8s.io/api/core/v1",
|
||||
"k8s.io/apimachinery/pkg/api/errors",
|
||||
|
||||
+67
-17
@@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
BaremetalAgent *SBaremetalAgent
|
||||
baremetalAgent *SBaremetalAgent
|
||||
)
|
||||
|
||||
type SZone struct {
|
||||
@@ -31,6 +31,7 @@ type SBaremetalAgent struct {
|
||||
AgentId string
|
||||
AgentName string
|
||||
Zone *SZone
|
||||
Manager *SBaremetalManager
|
||||
}
|
||||
|
||||
func newBaremetalAgent() (*SBaremetalAgent, error) {
|
||||
@@ -45,6 +46,7 @@ func newBaremetalAgent() (*SBaremetalAgent, error) {
|
||||
if len(ips) == 0 {
|
||||
return nil, fmt.Errorf("Interface %s ip address not found", o.Options.ListenInterface)
|
||||
}
|
||||
log.Debugf("Interface %s ip address: %v", iface.Name, ips)
|
||||
|
||||
agent := &SBaremetalAgent{
|
||||
ListenInterface: iface,
|
||||
@@ -56,7 +58,7 @@ func GetAdminSession() *mcclient.ClientSession {
|
||||
return auth.GetAdminSession(o.Options.Region, "v2")
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetListenIP() (net.IP, error) {
|
||||
func (agent *SBaremetalAgent) GetListenIPs() ([]net.IP, error) {
|
||||
ips, err := getIfaceIPs(agent.ListenInterface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -64,7 +66,42 @@ func (agent *SBaremetalAgent) GetListenIP() (net.IP, error) {
|
||||
if len(ips) == 0 {
|
||||
return nil, fmt.Errorf("Interface %s ip address not found", agent.ListenInterface.Name)
|
||||
}
|
||||
return ips[0], nil
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetListenIP() (net.IP, error) {
|
||||
ips, err := agent.GetListenIPs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if o.Options.ListenAddress == "" {
|
||||
return ips[0], nil
|
||||
}
|
||||
if o.Options.ListenAddress == "0.0.0.0" {
|
||||
return net.ParseIP(o.Options.ListenAddress), nil
|
||||
}
|
||||
for _, ip := range ips {
|
||||
if ip.String() == o.Options.ListenAddress {
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Not found ListenAddress %s on %s", o.Options.ListenAddress, o.Options.ListenInterface)
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetAccessIP() (net.IP, error) {
|
||||
ips, err := agent.GetListenIPs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if o.Options.AccessAddress == "" {
|
||||
return ips[0], nil
|
||||
}
|
||||
for _, ip := range ips {
|
||||
if ip.String() == o.Options.AccessAddress {
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Not found AccessAddress %s on %s", o.Options.AccessAddress, o.Options.ListenInterface)
|
||||
}
|
||||
|
||||
func getIfaceIPs(iface *net.Interface) ([]net.IP, error) {
|
||||
@@ -131,10 +168,15 @@ func (agent *SBaremetalAgent) register() error {
|
||||
return fmt.Errorf("Baremetal manager load config error: %v", err)
|
||||
}
|
||||
|
||||
agent.startServices(manager)
|
||||
agent.Manager = manager
|
||||
agent.startPXEServices(manager)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetManager() *SBaremetalManager {
|
||||
return agent.Manager
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) getZoneByIP(session *mcclient.ClientSession) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
listenIP, err := agent.GetListenIP()
|
||||
@@ -192,11 +234,11 @@ func (agent *SBaremetalAgent) fetchZone(session *mcclient.ClientSession) error {
|
||||
|
||||
func (agent *SBaremetalAgent) createOrUpdateBaremetalAgent(session *mcclient.ClientSession) error {
|
||||
params := jsonutils.NewDict()
|
||||
listenIP, err := agent.GetListenIP()
|
||||
naccessIP, err := agent.GetAccessIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Add(jsonutils.NewString(listenIP.String()), "access_ip")
|
||||
params.Add(jsonutils.NewString(naccessIP.String()), "access_ip")
|
||||
ret, err := modules.Baremetalagents.List(session, params)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -218,7 +260,7 @@ func (agent *SBaremetalAgent) createOrUpdateBaremetalAgent(session *mcclient.Cli
|
||||
managerUri, _ := cloudBmAgent.GetString("manager_uri")
|
||||
zoneId, _ := cloudBmAgent.GetString("zone_id")
|
||||
agentId, _ := cloudBmAgent.GetString("id")
|
||||
if listenIP.String() != accessIP ||
|
||||
if naccessIP.String() != accessIP ||
|
||||
agent.GetManagerUri() != managerUri ||
|
||||
zoneId != agent.Zone.Id {
|
||||
cloudObj, err = agent.updateBaremetalAgent(session, agentId)
|
||||
@@ -245,24 +287,24 @@ func (agent *SBaremetalAgent) createOrUpdateBaremetalAgent(session *mcclient.Cli
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetManagerUri() string {
|
||||
listenIP, _ := agent.GetListenIP()
|
||||
accessIP, _ := agent.GetAccessIP()
|
||||
proto := "http"
|
||||
if o.Options.EnableSsl {
|
||||
proto = "https"
|
||||
}
|
||||
return fmt.Sprintf("%s://%s:%d", proto, listenIP, o.Options.Port)
|
||||
return fmt.Sprintf("%s://%s:%d", proto, accessIP, o.Options.Port)
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) getCreateUpdateInfo() (jsonutils.JSONObject, error) {
|
||||
listenIP, err := agent.GetListenIP()
|
||||
accessIP, err := agent.GetAccessIP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params := jsonutils.NewDict()
|
||||
if agent.AgentId == "" {
|
||||
params.Add(jsonutils.NewString(fmt.Sprintf("baremetal_%s", listenIP)), "name")
|
||||
params.Add(jsonutils.NewString(fmt.Sprintf("baremetal_%s", accessIP)), "name")
|
||||
}
|
||||
params.Add(jsonutils.NewString(listenIP.String()), "access_ip")
|
||||
params.Add(jsonutils.NewString(accessIP.String()), "access_ip")
|
||||
params.Add(jsonutils.NewString(agent.GetManagerUri()), "manager_uri")
|
||||
params.Add(jsonutils.NewString(agent.Zone.Id), "zone_id")
|
||||
return params, nil
|
||||
@@ -306,7 +348,7 @@ func (agent *SBaremetalAgent) disableUDPOffloading() {
|
||||
offGso.Run()
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) startServices(manager *SBaremetalManager) {
|
||||
func (agent *SBaremetalAgent) startPXEServices(manager *SBaremetalManager) {
|
||||
listenIP, err := agent.GetListenIP()
|
||||
if err != nil {
|
||||
log.Fatalf("Get listen ip address error: %v", err)
|
||||
@@ -326,15 +368,23 @@ func (agent *SBaremetalAgent) startServices(manager *SBaremetalManager) {
|
||||
|
||||
func Start() error {
|
||||
var err error
|
||||
if BaremetalAgent != nil {
|
||||
log.Warningf("Global BaremetalAgent already start")
|
||||
if baremetalAgent != nil {
|
||||
log.Warningf("Global baremetalAgent already start")
|
||||
return nil
|
||||
}
|
||||
BaremetalAgent, err = newBaremetalAgent()
|
||||
baremetalAgent, err = newBaremetalAgent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
BaremetalAgent.startRegister()
|
||||
baremetalAgent.startRegister()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetBaremetalAgent() *SBaremetalAgent {
|
||||
return baremetalAgent
|
||||
}
|
||||
|
||||
func GetBaremetalManager() *SBaremetalManager {
|
||||
return GetBaremetalAgent().GetManager()
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/tasks"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
@@ -78,12 +80,21 @@ func (ctx *Context) Request() *http.Request {
|
||||
return ctx.request
|
||||
}
|
||||
|
||||
func (ctx *Context) RequestRemoteIP() string {
|
||||
remoteAddr := ctx.Request().RemoteAddr
|
||||
return strings.Split(remoteAddr, ":")[0]
|
||||
}
|
||||
|
||||
func (ctx *Context) ResponseOk() {
|
||||
obj := jsonutils.NewDict()
|
||||
obj.Add(jsonutils.NewString("ok"), "result")
|
||||
appsrv.SendJSON(ctx.writer, obj)
|
||||
}
|
||||
|
||||
func (ctx *Context) GetBaremetalManager() *SBaremetalManager {
|
||||
return GetBaremetalManager()
|
||||
}
|
||||
|
||||
type handlerFunc func(ctx *Context)
|
||||
|
||||
func authMiddleware(h handlerFunc) appsrv.FilterHandler {
|
||||
@@ -100,7 +111,21 @@ func handleBaremetalNotify(ctx *Context) {
|
||||
ctx.ResponseError(httperrors.NewInputParameterError("Not found key in query"))
|
||||
return
|
||||
}
|
||||
remoteAddr := ctx.Request().RemoteAddr
|
||||
log.Debugf("===Get key %q from remote address: %s, bmId: %s", key, remoteAddr, bmId)
|
||||
remoteAddr := ctx.RequestRemoteIP()
|
||||
baremetal := ctx.GetBaremetalManager().GetBaremetalById(bmId)
|
||||
if baremetal == nil {
|
||||
ctx.ResponseError(httperrors.NewNotFoundError("Not found baremetal by id: %s", bmId))
|
||||
return
|
||||
}
|
||||
err = baremetal.SaveSSHConfig(remoteAddr, key)
|
||||
if err != nil {
|
||||
log.Errorf("Save baremetal %s ssh config: %v", bmId, err)
|
||||
}
|
||||
|
||||
// execute BaremetalServerPrepareTask
|
||||
task := baremetal.GetTask()
|
||||
if task != nil {
|
||||
task.(*tasks.SBaremetalServerPrepareTask).SSHExecute(task, remoteAddr, key, nil)
|
||||
}
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
+248
-22
@@ -6,6 +6,8 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -14,14 +16,19 @@ import (
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
"yunion.io/x/pkg/util/workqueue"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/pxe"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/status"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/tasks"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalManager struct {
|
||||
@@ -105,6 +112,15 @@ func (m *SBaremetalManager) initBaremetal(session *mcclient.ClientSession, bmId
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) CleanBaremetal(bmId string) {
|
||||
bm := m.baremetals.Pop(bmId)
|
||||
if bm != nil {
|
||||
bm.Stop()
|
||||
}
|
||||
path := bm.GetDir()
|
||||
procutils.NewCommand("rm", "-fr", path).Run()
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) updateBaremetal(session *mcclient.ClientSession, bmId string) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.JSONTrue, "is_baremetal")
|
||||
@@ -122,7 +138,7 @@ func (m *SBaremetalManager) AddBaremetal(desc jsonutils.JSONObject) (pxe.IBareme
|
||||
return nil, fmt.Errorf("Not found baremetal id in desc %s", desc)
|
||||
}
|
||||
if instance, ok := m.baremetals.Get(id); ok {
|
||||
return instance, nil
|
||||
return instance, instance.SaveDesc(desc)
|
||||
}
|
||||
bm, err := newBaremetalInstance(m, desc)
|
||||
if err != nil {
|
||||
@@ -132,6 +148,21 @@ func (m *SBaremetalManager) AddBaremetal(desc jsonutils.JSONObject) (pxe.IBareme
|
||||
return bm, nil
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) GetBaremetals() []*SBaremetalInstance {
|
||||
objs := make([]*SBaremetalInstance, 0)
|
||||
getter := func(key, val interface{}) bool {
|
||||
objs = append(objs, val.(*SBaremetalInstance))
|
||||
return true
|
||||
}
|
||||
m.baremetals.Range(getter)
|
||||
return objs
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) GetBaremetalById(bmId string) *SBaremetalInstance {
|
||||
obj, _ := m.baremetals.Get(bmId)
|
||||
return obj
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) GetBaremetalByMac(mac net.HardwareAddr) pxe.IBaremetalInstance {
|
||||
var obj *SBaremetalInstance
|
||||
getter := func(key, val interface{}) bool {
|
||||
@@ -148,6 +179,12 @@ func (m *SBaremetalManager) GetBaremetalByMac(mac net.HardwareAddr) pxe.IBaremet
|
||||
return obj
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) Stop() {
|
||||
for _, bm := range m.GetBaremetals() {
|
||||
bm.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
type sBaremetalMap struct {
|
||||
*sync.Map
|
||||
}
|
||||
@@ -174,15 +211,27 @@ func (m *sBaremetalMap) Delete(id string) {
|
||||
m.Map.Delete(id)
|
||||
}
|
||||
|
||||
func (m *sBaremetalMap) Pop(id string) *SBaremetalInstance {
|
||||
obj, exist := m.Get(id)
|
||||
if exist {
|
||||
m.Delete(id)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
type SBaremetalInstance struct {
|
||||
manager *SBaremetalManager
|
||||
desc jsonutils.JSONObject
|
||||
manager *SBaremetalManager
|
||||
desc jsonutils.JSONObject
|
||||
descLock *sync.Mutex
|
||||
taskQueue *tasks.TaskQueue
|
||||
}
|
||||
|
||||
func newBaremetalInstance(man *SBaremetalManager, desc jsonutils.JSONObject) (*SBaremetalInstance, error) {
|
||||
bm := &SBaremetalInstance{
|
||||
manager: man,
|
||||
desc: desc,
|
||||
manager: man,
|
||||
desc: desc,
|
||||
descLock: new(sync.Mutex),
|
||||
taskQueue: tasks.NewTaskQueue(),
|
||||
}
|
||||
err := os.MkdirAll(bm.GetDir(), 0755)
|
||||
if err != nil {
|
||||
@@ -212,6 +261,10 @@ func (b *SBaremetalInstance) GetName() string {
|
||||
return id
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) Stop() {
|
||||
// TODO:
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetDir() string {
|
||||
return filepath.Join(b.manager.configPath, b.GetId())
|
||||
}
|
||||
@@ -224,7 +277,7 @@ func (b *SBaremetalInstance) GetServerDescFilePath() string {
|
||||
return filepath.Join(b.GetDir(), "server")
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetSshConfigFilePath() string {
|
||||
func (b *SBaremetalInstance) GetSSHConfigFilePath() string {
|
||||
return filepath.Join(b.GetDir(), "ssh")
|
||||
}
|
||||
|
||||
@@ -237,14 +290,115 @@ func (b *SBaremetalInstance) GetStatus() string {
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SaveDesc(desc jsonutils.JSONObject) error {
|
||||
b.descLock.Lock()
|
||||
defer b.descLock.Unlock()
|
||||
b.desc = desc
|
||||
return ioutil.WriteFile(b.GetDescFilePath(), []byte(desc.String()), 0644)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SaveSSHConfig(remoteAddr string, key string) error {
|
||||
var err error
|
||||
key, err = utils.EncryptAESBase64(b.GetId(), key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sshConf := types.SSHConfig{
|
||||
Username: "root",
|
||||
Password: key,
|
||||
RemoteIP: remoteAddr,
|
||||
}
|
||||
conf := jsonutils.Marshal(sshConf)
|
||||
err = ioutil.WriteFile(b.GetSSHConfigFilePath(), []byte(conf.String()), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.SyncSSHConfig(sshConf)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetSSHConfig() (*types.SSHConfig, error) {
|
||||
path := b.GetSSHConfigFilePath()
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
conf := types.SSHConfig{}
|
||||
obj, err := jsonutils.Parse(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = obj.Unmarshal(&conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Password, err = utils.DescryptAESBase64(b.GetId(), conf.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &conf, nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) TestSSHConfig() bool {
|
||||
conf, err := b.GetSSHConfig()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if conf == nil {
|
||||
return false
|
||||
}
|
||||
sshCli, err := ssh.NewClient(conf.RemoteIP, 22, "root", conf.Password, "")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
ret, err := sshCli.Run("whoami")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(strings.Join(ret, ""), "root") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) ClearSSHConfig() {
|
||||
path := b.GetSSHConfigFilePath()
|
||||
err := os.Remove(path)
|
||||
if err != nil {
|
||||
log.Errorf("Clear ssh config %s error: %v", path, err)
|
||||
}
|
||||
emptyConfig := types.SSHConfig{
|
||||
Username: "None",
|
||||
Password: "None",
|
||||
RemoteIP: "None",
|
||||
}
|
||||
b.SyncSSHConfig(emptyConfig)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SyncSSHConfig(conf types.SSHConfig) error {
|
||||
session := b.manager.GetClientSession()
|
||||
var err error
|
||||
// encrypt twice
|
||||
conf.Password, err = utils.EncryptAESBase64(b.GetId(), conf.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := jsonutils.Marshal(conf)
|
||||
_, err = modules.Hosts.SetMetadata(session, b.GetId(), data)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SyncStatusBackground() {
|
||||
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SyncStatus(status string) {
|
||||
log.Infof("sync baremetal %s status %s", b.GetName(), status)
|
||||
// TODO
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) getNicInfo() *types.NicInfo {
|
||||
nicInfo := types.NicInfo{}
|
||||
err := b.desc.Unmarshal(&nicInfo)
|
||||
@@ -283,7 +437,7 @@ func (b *SBaremetalInstance) getNicByMac(mac net.HardwareAddr) *types.Nic {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) getAdminNic() *types.Nic {
|
||||
func (b *SBaremetalInstance) GetAdminNic() *types.Nic {
|
||||
return b.getNicByType(NIC_TYPE_ADMIN)
|
||||
}
|
||||
|
||||
@@ -303,7 +457,7 @@ func (b *SBaremetalInstance) GetIPMINic(cliMac net.HardwareAddr) *types.Nic {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetDHCPConfig(cliMac net.HardwareAddr) (*pxe.ResponseConfig, error) {
|
||||
func (b *SBaremetalInstance) GetDHCPConfig(cliMac net.HardwareAddr) (*dhcp.ResponseConfig, error) {
|
||||
/*
|
||||
if self.get_server() is not None and (self.get_task() is None or not self.get_task().__pxe_boot__)
|
||||
nic = self.get_server().get_nic_by_mac(mac)
|
||||
@@ -319,8 +473,8 @@ func (b *SBaremetalInstance) GetDHCPConfig(cliMac net.HardwareAddr) (*pxe.Respon
|
||||
return b.getDHCPConfig(nic, "", false, 0)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetPXEDHCPConfig(arch uint16) (*pxe.ResponseConfig, error) {
|
||||
return b.getDHCPConfig(b.getAdminNic(), "", true, arch)
|
||||
func (b *SBaremetalInstance) GetPXEDHCPConfig(arch uint16) (*dhcp.ResponseConfig, error) {
|
||||
return b.getDHCPConfig(b.GetAdminNic(), "", true, arch)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) getDHCPConfig(
|
||||
@@ -328,15 +482,15 @@ func (b *SBaremetalInstance) getDHCPConfig(
|
||||
hostName string,
|
||||
isPxe bool,
|
||||
arch uint16,
|
||||
) (*pxe.ResponseConfig, error) {
|
||||
) (*dhcp.ResponseConfig, error) {
|
||||
if hostName == "" {
|
||||
hostName = b.GetName()
|
||||
}
|
||||
listenIP, err := b.manager.Agent.GetListenIP()
|
||||
accessIP, err := b.manager.Agent.GetAccessIP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return GetNicDHCPConfig(nic, listenIP.String(), hostName, isPxe, arch)
|
||||
return GetNicDHCPConfig(nic, accessIP.String(), hostName, isPxe, arch)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetNotifyUrl() string {
|
||||
@@ -355,7 +509,23 @@ label start
|
||||
auth.GetTokenString(), b.GetNotifyUrl())
|
||||
}
|
||||
|
||||
// TODO: imple
|
||||
func (b *SBaremetalInstance) GetTaskQueue() *tasks.TaskQueue {
|
||||
return b.taskQueue
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetTask() tasks.ITask {
|
||||
return b.taskQueue.GetTask()
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SetTask(task tasks.ITask) {
|
||||
b.taskQueue.AppendTask(task)
|
||||
if reflect.DeepEqual(task, b.taskQueue.GetTask()) {
|
||||
//tasks.ExecuteTask(task, nil)
|
||||
log.Infof("Set task equal")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: impl
|
||||
func (b *SBaremetalInstance) InitAdminNetif(
|
||||
cliMac net.HardwareAddr,
|
||||
netConf *types.NetworkConfig,
|
||||
@@ -363,9 +533,23 @@ func (b *SBaremetalInstance) InitAdminNetif(
|
||||
) error {
|
||||
// start prepare task
|
||||
// sync status to PREPARE
|
||||
if nicType == types.NIC_TYPE_ADMIN &&
|
||||
utils.IsInStringArray(b.GetStatus(),
|
||||
[]string{status.INIT, status.PREPARE, status.PREPARE_FAIL, status.UNKNOWN}) &&
|
||||
b.GetTask() == nil && b.GetServer() == nil {
|
||||
b.SetTask(tasks.NewBaremetalServerPrepareTask(b))
|
||||
b.SyncStatus(status.PREPARE)
|
||||
}
|
||||
|
||||
nic := b.getNicByMac(cliMac)
|
||||
if nic == nil || nic.WireId == "" {
|
||||
// Attach wire
|
||||
_, err := b.attachWire(cliMac, netConf.WireId, nicType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.postAttachWire(cliMac, nicType)
|
||||
} else if nic.IpAddr == "" {
|
||||
return b.postAttachWire(cliMac, nicType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -376,12 +560,16 @@ func (b *SBaremetalInstance) RegisterNetif(
|
||||
) error {
|
||||
nic := b.getNicByMac(cliMac)
|
||||
if nic == nil || nic.WireId == "" || nic.WireId != netConf.WireId {
|
||||
return b.attachWire(cliMac, netConf.WireId, nic.Type)
|
||||
desc, err := b.attachWire(cliMac, netConf.WireId, nic.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.SaveDesc(desc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) attachWire(mac net.HardwareAddr, wireId string, nicType string) error {
|
||||
func (b *SBaremetalInstance) attachWire(mac net.HardwareAddr, wireId string, nicType string) (jsonutils.JSONObject, error) {
|
||||
session := b.manager.GetClientSession()
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(mac.String()), "mac")
|
||||
@@ -390,11 +578,25 @@ func (b *SBaremetalInstance) attachWire(mac net.HardwareAddr, wireId string, nic
|
||||
}
|
||||
params.Add(jsonutils.NewString(wireId), "wire")
|
||||
params.Add(jsonutils.JSONTrue, "link_up")
|
||||
_, err := modules.Hosts.PerformAction(session, b.GetId(), "add-netif", params)
|
||||
return err
|
||||
return modules.Hosts.PerformAction(session, b.GetId(), "add-netif", params)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) enableWire(mac net.HardwareAddr, ipAddr string, nicType string) error {
|
||||
func (b *SBaremetalInstance) postAttachWire(mac net.HardwareAddr, nicType string) error {
|
||||
ipAddr := ""
|
||||
if nicType == types.NIC_TYPE_IPMI {
|
||||
oldIPMIConf := b.GetRawIPMIConfig()
|
||||
if oldIPMIConf != nil && oldIPMIConf.IpAddr != "" {
|
||||
ipAddr = oldIPMIConf.IpAddr
|
||||
}
|
||||
}
|
||||
desc, err := b.enableWire(mac, ipAddr, nicType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.SaveDesc(desc)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) enableWire(mac net.HardwareAddr, ipAddr string, nicType string) (jsonutils.JSONObject, error) {
|
||||
session := b.manager.GetClientSession()
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(mac.String()), "mac")
|
||||
@@ -407,6 +609,30 @@ func (b *SBaremetalInstance) enableWire(mac net.HardwareAddr, ipAddr string, nic
|
||||
if nicType == types.NIC_TYPE_IPMI {
|
||||
params.Add(jsonutils.NewString("stepup"), "alloc_dir") // alloc bottom up
|
||||
}
|
||||
_, err := modules.Hosts.PerformAction(session, b.GetId(), "enable-netif", params)
|
||||
return err
|
||||
return modules.Hosts.PerformAction(session, b.GetId(), "enable-netif", params)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetRawIPMIConfig() *types.IPMIInfo {
|
||||
ipmiInfo := types.IPMIInfo{}
|
||||
err := b.desc.Unmarshal(&ipmiInfo, "ipmi_info")
|
||||
if err != nil {
|
||||
log.Errorf("Unmarshal IPMIInfo error: %v", err)
|
||||
return nil
|
||||
}
|
||||
if ipmiInfo.Password != "" {
|
||||
ipmiInfo.Password, err = utils.DescryptAESBase64(b.GetId(), ipmiInfo.Password)
|
||||
if err != nil {
|
||||
log.Errorf("DescryptAESBase64 IPMI password error: %v", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return &ipmiInfo
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetServer() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) DoPowerShutdown(soft bool) {
|
||||
log.Infof("DoPowerShutdown")
|
||||
}
|
||||
|
||||
+13
-3
@@ -3,11 +3,13 @@ package baremetal
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/pxe"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/dhcp"
|
||||
)
|
||||
|
||||
func GetNicDHCPConfig(
|
||||
@@ -16,7 +18,13 @@ func GetNicDHCPConfig(
|
||||
hostName string,
|
||||
isPxe bool,
|
||||
arch uint16,
|
||||
) (*pxe.ResponseConfig, error) {
|
||||
) (*dhcp.ResponseConfig, error) {
|
||||
if n == nil {
|
||||
return nil, fmt.Errorf("Nic is nil")
|
||||
}
|
||||
if n.IpAddr == "" {
|
||||
return nil, fmt.Errorf("Nic no ip address")
|
||||
}
|
||||
ipAddr, err := netutils.NewIPV4Addr(n.IpAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parse IP address error: %q", n.IpAddr)
|
||||
@@ -24,7 +32,7 @@ func GetNicDHCPConfig(
|
||||
|
||||
subnetMask := net.ParseIP(netutils.Masklen2Mask(n.MaskLen).String())
|
||||
|
||||
conf := &pxe.ResponseConfig{
|
||||
conf := &dhcp.ResponseConfig{
|
||||
ServerIP: net.ParseIP(serverIP),
|
||||
ClientIP: net.ParseIP(ipAddr.String()),
|
||||
Gateway: net.ParseIP(n.Gateway),
|
||||
@@ -35,6 +43,8 @@ func GetNicDHCPConfig(
|
||||
OsName: "Linux",
|
||||
Hostname: hostName,
|
||||
// TODO: routes opt
|
||||
LeaseTime: time.Duration(o.Options.DhcpLeaseTime) * time.Second,
|
||||
RenewalTime: time.Duration(o.Options.DhcpRenewalTime) * time.Second,
|
||||
}
|
||||
|
||||
if isPxe {
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
type BaremetalOptions struct {
|
||||
cloudcommon.Options
|
||||
|
||||
ListenInterface string `help:"Master address of host server" default:"br0"`
|
||||
ListenInterface string `help:"Master net interface of baremetal server" default:"br0"`
|
||||
AccessAddress string `help:"Management IP address of baremetal server, only need to use when multiple address bind to ListenInterface"`
|
||||
ListenAddress string `help:"PXE serve IP address to select when multiple address bind to ListenInterface" default:"0.0.0.0"`
|
||||
TftpRoot string `help:"tftp root directory"`
|
||||
AutoRegisterBaremetal bool `default:"true" help:"Automatically create a baremetal instance"`
|
||||
BaremetalsPath string `default:"/opt/cloud/workspace/baremetals" help:"Path for baremetals configuration files"`
|
||||
|
||||
+13
-145
@@ -6,50 +6,16 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
dhcp "go.universe.tf/netboot/dhcp4"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
)
|
||||
|
||||
const (
|
||||
PXECLIENT = "PXEClient"
|
||||
|
||||
OptClientArchitecture dhcp.Option = 93
|
||||
OptClientNetworkInterfaceIdentifier dhcp.Option = 94
|
||||
OptClientMachineIdentifier dhcp.Option = 97
|
||||
)
|
||||
|
||||
func (s *Server) serveDHCP(conn *dhcp.Conn) error {
|
||||
for {
|
||||
pkt, intf, err := conn.RecvDHCP()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Receiving DHCP packet: %s", err)
|
||||
}
|
||||
if intf == nil {
|
||||
return fmt.Errorf("Received DHCP packet with no interface information (this is a violation of dhcp4.Conn's contract)")
|
||||
}
|
||||
go func() {
|
||||
h := &DHCPHandler{baremetalManager: s.BaremetalManager}
|
||||
resp, err := h.ServeDHCP(pkt)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP] handler serve error: %v", err)
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
log.Warningf("[DHCP] hander response null packet")
|
||||
return
|
||||
}
|
||||
log.Debugf("[DHCP] send response packet: %s to interface: %#v", resp.DebugString(), intf)
|
||||
if err = conn.SendDHCP(resp, intf); err != nil {
|
||||
log.Errorf("[DHCP] failed to response packet for %s: %v", pkt.HardwareAddr, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
func (s *Server) serveDHCP(srv *dhcp.DHCPServer, handler dhcp.DHCPHandler) error {
|
||||
return srv.ListenAndServe(handler)
|
||||
}
|
||||
|
||||
type NetworkInterfaceIdent struct {
|
||||
@@ -85,27 +51,14 @@ func (h *DHCPHandler) ServeDHCP(pkt *dhcp.Packet) (*dhcp.Packet, error) {
|
||||
}
|
||||
log.Infof("======Parse packet end: %#v", h)
|
||||
|
||||
//if h.RelayAddr.String() == "0.0.0.0" {
|
||||
//return nil, fmt.Errorf("Request not from a DHCP relay, ignore mac: %s", h.ClientMac)
|
||||
//}
|
||||
if h.RelayAddr.String() == "0.0.0.0" {
|
||||
return nil, fmt.Errorf("Request not from a DHCP relay, ignore mac: %s", h.ClientMac)
|
||||
}
|
||||
conf, err := h.fetchConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.handleRequest(pkt, conf)
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) handleRequest(pkt *dhcp.Packet, conf *ResponseConfig) (*dhcp.Packet, error) {
|
||||
msgType := dhcp.MsgOffer
|
||||
if pkt.Type == dhcp.MsgRequest {
|
||||
reqAddr, _ := pkt.Options.IP(dhcp.OptRequestedIP)
|
||||
if reqAddr != nil && !conf.ClientIP.Equal(reqAddr) {
|
||||
msgType = dhcp.MsgNack
|
||||
} else {
|
||||
msgType = dhcp.MsgAck
|
||||
}
|
||||
}
|
||||
return makeDHCPReplyPacket(pkt, conf, msgType), nil
|
||||
return dhcp.MakeReplyPacket(pkt, conf)
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) parsePacket(pkt *dhcp.Packet) error {
|
||||
@@ -127,9 +80,9 @@ func (h *DHCPHandler) parsePacket(pkt *dhcp.Packet) error {
|
||||
switch optCode {
|
||||
case dhcp.OptVendorIdentifier:
|
||||
vendorClsId, err = h.Options.String(optCode)
|
||||
case OptClientArchitecture:
|
||||
case dhcp.OptClientArchitecture:
|
||||
cliArch, err = h.Options.Uint16(optCode)
|
||||
case OptClientNetworkInterfaceIdentifier:
|
||||
case dhcp.OptClientNetworkInterfaceIdentifier:
|
||||
netIfIdentBs, err := h.Options.Bytes(optCode)
|
||||
if err != nil {
|
||||
break
|
||||
@@ -140,7 +93,7 @@ func (h *DHCPHandler) parsePacket(pkt *dhcp.Packet) error {
|
||||
Minior: uint16(netIfIdentBs[2]),
|
||||
}
|
||||
log.Debugf("[DHCP] get network iface identifier: %#v", netIfIdent)
|
||||
case OptClientMachineIdentifier:
|
||||
case dhcp.OptClientMachineIdentifier:
|
||||
switch len(data) {
|
||||
case 0:
|
||||
// A missing GUID is invalid according to the spec, however
|
||||
@@ -166,7 +119,7 @@ func (h *DHCPHandler) parsePacket(pkt *dhcp.Packet) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) fetchConfig() (*ResponseConfig, error) {
|
||||
func (h *DHCPHandler) fetchConfig() (*dhcp.ResponseConfig, error) {
|
||||
// 1. find_network_conf
|
||||
netConf, err := h.findNetworkConf(false)
|
||||
if err != nil {
|
||||
@@ -178,7 +131,7 @@ func (h *DHCPHandler) fetchConfig() (*ResponseConfig, error) {
|
||||
//
|
||||
if h.isPXERequest() {
|
||||
// handle PXE DHCP request
|
||||
log.Infof("DHCP relay from %s(%s) for %s, find matched networks: %s", h.RelayAddr, h.ClientAddr, h.ClientMac, netConf)
|
||||
log.Infof("DHCP relay from %s(%s) for %s, find matched networks: %#v", h.RelayAddr, h.ClientAddr, h.ClientMac, netConf)
|
||||
bmDesc, err := h.createOrUpdateBaremetal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -218,83 +171,6 @@ func (h *DHCPHandler) fetchConfig() (*ResponseConfig, error) {
|
||||
}
|
||||
}
|
||||
|
||||
type ResponseConfig struct {
|
||||
OsName string
|
||||
ServerIP net.IP // OptServerIdentifier 54
|
||||
ClientIP net.IP
|
||||
Gateway net.IP // OptRouters 3
|
||||
Domain string // OptDomainName 15
|
||||
LeaseTime uint32 // OptLeaseTime 51
|
||||
RenewalTime uint32 // OptRenewalTime 58
|
||||
BroadcastAddr net.IP // OptBroadcastAddr 28
|
||||
Hostname string // OptHostname 12
|
||||
SubnetMask net.IP // OptSubnetMask 1
|
||||
DNSServer net.IP // OptDNSServers
|
||||
Routes interface{} // TODO: 249 for windows, 121 for linux
|
||||
|
||||
// TFTP config
|
||||
BootServer string
|
||||
BootFile string
|
||||
}
|
||||
|
||||
func getPacketVendorClassId(pkt *dhcp.Packet) string {
|
||||
vendorClsId, _ := pkt.Options.String(dhcp.OptVendorIdentifier)
|
||||
return vendorClsId
|
||||
}
|
||||
|
||||
func makeDHCPReplyPacket(pkt *dhcp.Packet, conf *ResponseConfig, msgType dhcp.MessageType) *dhcp.Packet {
|
||||
if conf.OsName == "" {
|
||||
if vendorClsId := getPacketVendorClassId(pkt); vendorClsId != "" && strings.HasPrefix(vendorClsId, "MSFT ") {
|
||||
conf.OsName = "win"
|
||||
}
|
||||
}
|
||||
resp := &dhcp.Packet{
|
||||
Type: msgType,
|
||||
TransactionID: pkt.TransactionID,
|
||||
HardwareAddr: pkt.HardwareAddr,
|
||||
RelayAddr: pkt.RelayAddr,
|
||||
ServerAddr: conf.ServerIP,
|
||||
Options: make(dhcp.Options),
|
||||
}
|
||||
if msgType == dhcp.MsgNack {
|
||||
return resp
|
||||
}
|
||||
resp.YourAddr = conf.ClientIP
|
||||
resp.Options[dhcp.OptServerIdentifier] = conf.ServerIP
|
||||
if conf.SubnetMask != nil {
|
||||
resp.Options[dhcp.OptSubnetMask] = conf.SubnetMask
|
||||
}
|
||||
if conf.Gateway != nil {
|
||||
resp.Options[dhcp.OptRouters] = conf.Gateway
|
||||
}
|
||||
if conf.Domain != "" {
|
||||
resp.Options[dhcp.OptDomainName] = []byte(conf.Domain)
|
||||
}
|
||||
if conf.BroadcastAddr != nil {
|
||||
resp.Options[dhcp.OptBroadcastAddr] = conf.BroadcastAddr
|
||||
}
|
||||
if conf.Hostname != "" {
|
||||
resp.Options[dhcp.OptHostname] = []byte(conf.Hostname)
|
||||
}
|
||||
if conf.DNSServer != nil {
|
||||
resp.Options[dhcp.OptDNSServers] = conf.DNSServer
|
||||
}
|
||||
if conf.BootServer != "" {
|
||||
resp.BootServerName = conf.BootServer
|
||||
}
|
||||
if conf.BootFile != "" {
|
||||
resp.BootFilename = conf.BootFile
|
||||
// says the server should identify itself as a PXEClient vendor
|
||||
// type, even though it's a server. Strange.
|
||||
resp.Options[dhcp.OptVendorIdentifier] = []byte(PXECLIENT)
|
||||
}
|
||||
if pkt.Options[OptClientMachineIdentifier] != nil {
|
||||
resp.Options[OptClientMachineIdentifier] = pkt.Options[OptClientMachineIdentifier]
|
||||
}
|
||||
// TODO: routes support
|
||||
return resp
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) findNetworkConf(filterUseIp bool) (*types.NetworkConfig, error) {
|
||||
params := jsonutils.NewDict()
|
||||
if filterUseIp {
|
||||
@@ -396,15 +272,7 @@ func (h *DHCPHandler) doInitBaremetalAdminNetif(desc jsonutils.JSONObject) error
|
||||
|
||||
func (h *DHCPHandler) isPXERequest() bool {
|
||||
pkt := h.packet
|
||||
if pkt.Type != dhcp.MsgDiscover {
|
||||
log.Warningf("packet is %s, not %s", pkt.Type, dhcp.MsgDiscover)
|
||||
return false
|
||||
}
|
||||
|
||||
if pkt.Options[93] == nil {
|
||||
log.Warningf("not a PXE boot request (missing option 93)")
|
||||
}
|
||||
return true
|
||||
return dhcp.IsPXERequest(pkt)
|
||||
}
|
||||
|
||||
func (s *Server) validateDHCP(pkt *dhcp.Packet) (Machine, Firmware, error) {
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package pxe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pin/tftp"
|
||||
"go.universe.tf/netboot/dhcp4"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
@@ -79,10 +78,11 @@ type IBaremetalManager interface {
|
||||
type IBaremetalInstance interface {
|
||||
NeedPXEBoot() bool
|
||||
GetIPMINic(cliMac net.HardwareAddr) *types.Nic
|
||||
GetPXEDHCPConfig(arch uint16) (*ResponseConfig, error)
|
||||
GetDHCPConfig(cliMac net.HardwareAddr) (*ResponseConfig, error)
|
||||
GetPXEDHCPConfig(arch uint16) (*dhcp.ResponseConfig, error)
|
||||
GetDHCPConfig(cliMac net.HardwareAddr) (*dhcp.ResponseConfig, error)
|
||||
InitAdminNetif(cliMac net.HardwareAddr, netConf *types.NetworkConfig, nicType string) error
|
||||
RegisterNetif(cliMac net.HardwareAddr, netConf *types.NetworkConfig) error
|
||||
GetTFTPResponse() string
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
@@ -105,26 +105,23 @@ func (s *Server) Serve() error {
|
||||
if s.TFTPPort == 0 {
|
||||
s.TFTPPort = portTFTP
|
||||
}
|
||||
tftpHandler, err := NewTFTPHandler(s.TFTPRootDir)
|
||||
tftpHandler, err := NewTFTPHandler(s.TFTPRootDir, s.BaremetalManager)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tftpSrv := tftp.NewServer(tftpHandler.ReadHandler, nil)
|
||||
tftpSrv.SetTimeout(5 * time.Second)
|
||||
|
||||
newDHCP := dhcp4.NewConn
|
||||
dhcp, err := newDHCP(fmt.Sprintf("%s:%d", s.Address, s.DHCPPort))
|
||||
if err != nil {
|
||||
return fmt.Errorf("New DHCP error: %v", err)
|
||||
}
|
||||
dhcpSrv := dhcp.NewDHCPServer(s.Address, s.DHCPPort)
|
||||
|
||||
s.errs = make(chan error)
|
||||
|
||||
go func() { s.errs <- s.serveDHCP(dhcp) }()
|
||||
dhcpHandler := &DHCPHandler{baremetalManager: s.BaremetalManager}
|
||||
|
||||
go func() { s.errs <- s.serveDHCP(dhcpSrv, dhcpHandler) }()
|
||||
go func() { s.errs <- s.serveTFTP(tftpSrv) }()
|
||||
|
||||
err = <-s.errs
|
||||
dhcp.Close()
|
||||
tftpSrv.Shutdown()
|
||||
return err
|
||||
}
|
||||
|
||||
+14
-16
@@ -19,14 +19,18 @@ var (
|
||||
)
|
||||
|
||||
type TFTPHandler struct {
|
||||
RootDir string
|
||||
RootDir string
|
||||
BaremetalManager IBaremetalManager
|
||||
}
|
||||
|
||||
func NewTFTPHandler(rootDir string) (*TFTPHandler, error) {
|
||||
func NewTFTPHandler(rootDir string, baremetalManager IBaremetalManager) (*TFTPHandler, error) {
|
||||
if _, err := os.Stat(rootDir); err != nil {
|
||||
return nil, fmt.Errorf("TFTP root dir %q stat error: %v", rootDir, err)
|
||||
}
|
||||
return &TFTPHandler{rootDir}, nil
|
||||
return &TFTPHandler{
|
||||
RootDir: rootDir,
|
||||
BaremetalManager: baremetalManager,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ReadHandler is called when client starts file download from server
|
||||
@@ -56,21 +60,15 @@ func (h *TFTPHandler) ReadHandler(filename string, rf io.ReaderFrom) error {
|
||||
return h.sendFile(filename, rf)
|
||||
}
|
||||
|
||||
func getTFTPResponse() string {
|
||||
return fmt.Sprintf(
|
||||
`default start
|
||||
serial 1 115200
|
||||
label start
|
||||
menu label ^Start
|
||||
menu default
|
||||
kernel kernel
|
||||
append initrd=initramfs token=%s url=%s`,
|
||||
"token_str", "http://10.168.10.1")
|
||||
}
|
||||
|
||||
func (h *TFTPHandler) sendPxeLinuxCfgResponse(mac net.HardwareAddr, rf io.ReaderFrom) error {
|
||||
log.Debugf("[TFTP] client mac: %s", mac)
|
||||
respStr := getTFTPResponse()
|
||||
bmInstance := h.BaremetalManager.GetBaremetalByMac(mac)
|
||||
if bmInstance == nil {
|
||||
err := fmt.Errorf("Not found baremetal instance by mac: %s", mac)
|
||||
log.Errorf("Get baremetal error: %v", err)
|
||||
return err
|
||||
}
|
||||
respStr := bmInstance.GetTFTPResponse()
|
||||
log.Debugf("[TFTP] get tftp response config: %s", respStr)
|
||||
size := len(respStr)
|
||||
buffer := bytes.NewBufferString(respStr)
|
||||
|
||||
@@ -8,9 +8,12 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/baremetal"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
||||
)
|
||||
|
||||
func StartService() {
|
||||
consts.SetServiceType("baremetal")
|
||||
|
||||
cloudcommon.ParseOptions(&o.Options, &o.Options.Options, os.Args, "baremetal.conf")
|
||||
cloudcommon.InitAuth(&o.Options.Options, startAgent)
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package status
|
||||
|
||||
const (
|
||||
INIT = "init"
|
||||
PREPARE = "prepare"
|
||||
PREPARE_FAIL = "prepare_fail"
|
||||
READY = "ready"
|
||||
RUNNING = "running"
|
||||
MAINTAINING = "maintaining"
|
||||
START_MAINTAIN = "start_maintain"
|
||||
DELETING = "deleting"
|
||||
DELETE = "delete"
|
||||
DELETE_FAIL = "delete_fail"
|
||||
UNKNOWN = "unknown"
|
||||
SYNCING_STATUS = "syncing_status"
|
||||
SYNC = "sync"
|
||||
SYNC_FAIL = "sync_fail"
|
||||
START_CONVERT = "start_convert"
|
||||
CONVERTING = "converting"
|
||||
START_FAIL = "start_fail"
|
||||
STOP_FAIL = "stop_fail"
|
||||
)
|
||||
@@ -0,0 +1,217 @@
|
||||
package sysutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
)
|
||||
|
||||
func valueOfKeyword(line string, key string) *string {
|
||||
lo := strings.ToLower(line)
|
||||
ko := strings.ToLower(key)
|
||||
pos := strings.Index(lo, ko)
|
||||
if pos >= 0 {
|
||||
val := strings.TrimSpace(line[pos+len(key):])
|
||||
return &val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func dumpMapToObject(data map[string]string, obj interface{}) error {
|
||||
return jsonutils.Marshal(data).Unmarshal(obj)
|
||||
}
|
||||
|
||||
func ParseDMISysinfo(lines []string) (*types.DMIInfo, error) {
|
||||
if len(lines) == 0 {
|
||||
return nil, fmt.Errorf("Empty input")
|
||||
}
|
||||
keys := map[string]string{
|
||||
"manufacture": "Manufacturer:",
|
||||
"model": "Product Name:",
|
||||
"version": "Version:",
|
||||
"sn": "Serial Number:",
|
||||
}
|
||||
ret := make(map[string]string)
|
||||
for _, line := range lines {
|
||||
for key, keyword := range keys {
|
||||
val := valueOfKeyword(line, keyword)
|
||||
if val != nil {
|
||||
ret[key] = *val
|
||||
}
|
||||
}
|
||||
}
|
||||
info := types.DMIInfo{}
|
||||
err := dumpMapToObject(ret, &info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if strings.ToLower(info.Version) == "none" {
|
||||
info.Version = ""
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func ParseCPUInfo(lines []string) (*types.CPUInfo, error) {
|
||||
cnt := 0
|
||||
var (
|
||||
model string
|
||||
freq string
|
||||
cache string
|
||||
)
|
||||
lv := func(line string) string {
|
||||
return strings.TrimSpace(line[strings.Index(line, ":")+1:])
|
||||
}
|
||||
for _, line := range lines {
|
||||
if len(model) == 0 && strings.HasPrefix(line, "model name") {
|
||||
model = lv(line)
|
||||
}
|
||||
if len(freq) == 0 && strings.HasPrefix(line, "cpu MHz") {
|
||||
freq = lv(line)
|
||||
}
|
||||
if len(cache) == 0 && strings.HasPrefix(line, "cache size") {
|
||||
cache = strings.TrimSpace(line[strings.Index(line, ":")+1 : strings.Index(line, " KB")])
|
||||
}
|
||||
if strings.HasPrefix(line, "processor") {
|
||||
cnt += 1
|
||||
}
|
||||
}
|
||||
if len(model) == 0 {
|
||||
return nil, fmt.Errorf("Not found model name")
|
||||
}
|
||||
if len(freq) == 0 {
|
||||
return nil, fmt.Errorf("Not found cpu MHz")
|
||||
}
|
||||
if len(cache) == 0 {
|
||||
return nil, fmt.Errorf("Not found cache size")
|
||||
}
|
||||
model = strings.TrimSpace(model)
|
||||
info := &types.CPUInfo{
|
||||
Count: cnt,
|
||||
Model: model,
|
||||
}
|
||||
info.Cache, _ = strconv.Atoi(cache)
|
||||
freqF, _ := strconv.ParseFloat(freq, 32)
|
||||
info.Freq = int(freqF)
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func ParseDMICPUInfo(lines []string) *types.DMICPUInfo {
|
||||
cnt := 0
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "Processor Information") {
|
||||
cnt += 1
|
||||
}
|
||||
}
|
||||
return &types.DMICPUInfo{
|
||||
Nodes: cnt,
|
||||
}
|
||||
}
|
||||
|
||||
func ParseDMIMemInfo(lines []string) *types.DMIMemInfo {
|
||||
size := 0
|
||||
for _, line := range lines {
|
||||
val := valueOfKeyword(line, "Size:")
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
value := strings.ToLower(*val)
|
||||
if strings.HasSuffix(value, " mb") {
|
||||
sizeMb, err := strconv.Atoi(strings.TrimSuffix(value, " mb"))
|
||||
if err != nil {
|
||||
log.Errorf("parse MB error: %v", err)
|
||||
continue
|
||||
}
|
||||
size += sizeMb
|
||||
} else if strings.HasSuffix(value, " gb") {
|
||||
sizeGb, err := strconv.Atoi(strings.TrimSuffix(value, " gb"))
|
||||
if err != nil {
|
||||
log.Errorf("parse GB error: %v", err)
|
||||
continue
|
||||
}
|
||||
size += sizeGb * 1024
|
||||
}
|
||||
}
|
||||
return &types.DMIMemInfo{Total: size}
|
||||
}
|
||||
|
||||
func ParseDMIIPMIInfo(lines []string) bool {
|
||||
for _, line := range lines {
|
||||
val := valueOfKeyword(line, "Interface Type:")
|
||||
if val != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ParseNicInfo(lines []string) []*types.NicDevInfo {
|
||||
ret := make([]*types.NicDevInfo, 0)
|
||||
for _, line := range lines {
|
||||
dat := strings.Split(line, " ")
|
||||
if len(dat) > 4 {
|
||||
dev := dat[0]
|
||||
mac := dat[1]
|
||||
speed, _ := strconv.Atoi(dat[2])
|
||||
up := false
|
||||
if dat[3] == "1" {
|
||||
up = true
|
||||
}
|
||||
mtu, _ := strconv.Atoi(dat[4])
|
||||
ret = append(ret, &types.NicDevInfo{
|
||||
Dev: dev,
|
||||
Mac: mac,
|
||||
Speed: speed,
|
||||
Up: up,
|
||||
Mtu: mtu,
|
||||
})
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func ParseDiskInfo(lines []string, driver string) []*types.DiskInfo {
|
||||
ret := make([]*types.DiskInfo, 0)
|
||||
for _, line := range lines {
|
||||
data := strings.Split(line, " ")
|
||||
if len(data) <= 6 {
|
||||
continue
|
||||
}
|
||||
dev := data[0]
|
||||
sector, _ := strconv.Atoi(data[1])
|
||||
size := sector * 512 / 1024 / 1024
|
||||
block, _ := strconv.Atoi(data[2])
|
||||
rotate := false
|
||||
if data[3] == "1" {
|
||||
rotate = true
|
||||
}
|
||||
kernel := data[4]
|
||||
pciCls := data[5]
|
||||
modinfo := strings.Join(data[6:], " ")
|
||||
ret = append(ret, &types.DiskInfo{
|
||||
Dev: dev,
|
||||
Sector: sector,
|
||||
Block: block,
|
||||
Size: size,
|
||||
Rotate: rotate,
|
||||
ModuleInfo: modinfo,
|
||||
Kernel: kernel,
|
||||
PCIClass: pciCls,
|
||||
Driver: driver,
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func ParsePCIEDiskInfo(lines []string) []*types.DiskInfo {
|
||||
return ParseDiskInfo(lines, baremetal.DISK_DRIVER_PCIE)
|
||||
}
|
||||
|
||||
func ParseSCSIDiskInfo(lines []string) []*types.DiskInfo {
|
||||
return ParseDiskInfo(lines, baremetal.DISK_DRIVER_LINUX)
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package sysutils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
)
|
||||
|
||||
func Test_valueOfKeyword(t *testing.T) {
|
||||
type args struct {
|
||||
line string
|
||||
key string
|
||||
}
|
||||
t1 := "Manufacturer: LENOVO"
|
||||
w1 := "LENOVO"
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *string
|
||||
}{
|
||||
{
|
||||
name: "EmptyInput",
|
||||
args: args{
|
||||
line: "",
|
||||
key: "Family",
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "NormalInput",
|
||||
args: args{
|
||||
line: t1,
|
||||
key: "manufacturer:",
|
||||
},
|
||||
want: &w1,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := valueOfKeyword(tt.args.line, tt.args.key); got != nil && *got != *(tt.want) {
|
||||
t.Errorf("valueOfKeyword() = %q, want %q", *got, *(tt.want))
|
||||
} else if got == nil && tt.want != nil {
|
||||
t.Errorf("valueOfKeyword() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDMISysinfo(t *testing.T) {
|
||||
type args struct {
|
||||
lines []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *types.DMIInfo
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "EmptyInput",
|
||||
args: args{lines: nil},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "NormalInput",
|
||||
args: args{lines: []string{
|
||||
"Handle 0x000C, DMI type 1, 27 bytes",
|
||||
"System Information",
|
||||
" Manufacturer: LENOVO",
|
||||
" Product Name: 20J6CTO1WW",
|
||||
" Version: ThinkPad T470p",
|
||||
" Serial Number: PF112JKK",
|
||||
" UUID: bca177cc-2bce-11b2-a85c-e98996f19d2f",
|
||||
" SKU Number: LENOVO_MT_20J6_BU_Think_FM_ThinkPad T470p",
|
||||
}},
|
||||
want: &types.DMIInfo{
|
||||
Manufacture: "LENOVO",
|
||||
Model: "20J6CTO1WW",
|
||||
Version: "ThinkPad T470p",
|
||||
SN: "PF112JKK",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "NoneVersionInput",
|
||||
args: args{lines: []string{
|
||||
" Product Name: 20J6CTO1WW",
|
||||
" Version: None",
|
||||
" Serial Number: PF112JKK",
|
||||
}},
|
||||
want: &types.DMIInfo{
|
||||
Model: "20J6CTO1WW",
|
||||
Version: "",
|
||||
SN: "PF112JKK",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ParseDMISysinfo(tt.args.lines)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ParseDMISysinfo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ParseDMISysinfo() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCPUInfo(t *testing.T) {
|
||||
type args struct {
|
||||
lines []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *types.CPUInfo
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "NormalInput",
|
||||
args: args{lines: []string{
|
||||
"model name : Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz",
|
||||
"cpu MHz : 2793.238",
|
||||
"processor : 0",
|
||||
"processor : 1",
|
||||
"cache size : 16384 KB",
|
||||
}},
|
||||
want: &types.CPUInfo{
|
||||
Model: "Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz",
|
||||
Count: 2,
|
||||
Freq: 2793,
|
||||
Cache: 16384,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ParseCPUInfo(tt.args.lines)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ParseCPUInfo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ParseCPUInfo() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDMICPUInfo(t *testing.T) {
|
||||
type args struct {
|
||||
lines []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *types.DMICPUInfo
|
||||
}{
|
||||
{
|
||||
name: "NormalInput",
|
||||
args: args{
|
||||
lines: []string{"Processor Information"},
|
||||
},
|
||||
want: &types.DMICPUInfo{Nodes: 1},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ParseDMICPUInfo(tt.args.lines); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ParseDMICPUInfo() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDMIMemInfo(t *testing.T) {
|
||||
type args struct {
|
||||
lines []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *types.DMIMemInfo
|
||||
}{
|
||||
{
|
||||
name: "NormalInputMB",
|
||||
args: args{
|
||||
lines: []string{
|
||||
" Size: 16384 MB",
|
||||
" Size: No Module Installed"},
|
||||
},
|
||||
want: &types.DMIMemInfo{Total: 16384},
|
||||
},
|
||||
{
|
||||
name: "NormalInputGB",
|
||||
args: args{
|
||||
lines: []string{
|
||||
" Size: 16 GB",
|
||||
" Size: No Module Installed"},
|
||||
},
|
||||
want: &types.DMIMemInfo{Total: 16 * 1024},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ParseDMIMemInfo(tt.args.lines); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ParseDMIMemInfo() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNicInfo(t *testing.T) {
|
||||
type args struct {
|
||||
lines []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []*types.NicDevInfo
|
||||
}{
|
||||
{
|
||||
name: "NormalInput",
|
||||
args: args{
|
||||
lines: []string{
|
||||
"eth0 00:22:25:0b:ab:49 0 1 1500",
|
||||
"eth1 00:22:25:0b:ab:50 0 0 1500",
|
||||
},
|
||||
},
|
||||
want: []*types.NicDevInfo{
|
||||
&types.NicDevInfo{Dev: "eth0", Mac: "00:22:25:0b:ab:49", Speed: 0, Up: true, Mtu: 1500},
|
||||
&types.NicDevInfo{Dev: "eth1", Mac: "00:22:25:0b:ab:50", Speed: 0, Up: false, Mtu: 1500},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ParseNicInfo(tt.args.lines); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ParseNicInfo() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type Queue struct {
|
||||
objList *list.List
|
||||
objListLock *sync.Mutex
|
||||
}
|
||||
|
||||
func NewQueue() *Queue {
|
||||
return &Queue{
|
||||
objList: list.New(),
|
||||
objListLock: new(sync.Mutex),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Queue) Append(obj interface{}) *Queue {
|
||||
q.objListLock.Lock()
|
||||
defer q.objListLock.Unlock()
|
||||
q.objList.PushBack(obj)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *Queue) First() interface{} {
|
||||
q.objListLock.Lock()
|
||||
defer q.objListLock.Unlock()
|
||||
if q.objList.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return q.objList.Front().Value
|
||||
}
|
||||
|
||||
func (q *Queue) IsEmpty() bool {
|
||||
return q.First() == nil
|
||||
}
|
||||
|
||||
func (q *Queue) Pop() interface{} {
|
||||
q.objListLock.Lock()
|
||||
defer q.objListLock.Unlock()
|
||||
if q.objList.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
first := q.objList.Front()
|
||||
q.objList.Remove(first)
|
||||
return first.Value
|
||||
}
|
||||
|
||||
func (q *Queue) String() string {
|
||||
itemStrings := debugString(q.objList.Front())
|
||||
return fmt.Sprintf("%v", itemStrings)
|
||||
}
|
||||
|
||||
func debugString(elem *list.Element) []string {
|
||||
if elem == nil {
|
||||
return nil
|
||||
}
|
||||
strings := []string{fmt.Sprintf("%v", elem.Value)}
|
||||
rest := debugString(elem.Next())
|
||||
if rest != nil {
|
||||
strings = append(strings, rest...)
|
||||
}
|
||||
return strings
|
||||
}
|
||||
|
||||
type TaskQueue struct {
|
||||
*Queue
|
||||
}
|
||||
|
||||
type TaskStageFunc func(ctx context.Context, args interface{}) error
|
||||
|
||||
type SSHTaskStageFunc func(ctx context.Context, cli *ssh.Client, args interface{}) error
|
||||
|
||||
type sshStageWrapper struct {
|
||||
sshStage SSHTaskStageFunc
|
||||
remoteIP string
|
||||
password string
|
||||
}
|
||||
|
||||
func sshStageW(
|
||||
stage SSHTaskStageFunc,
|
||||
remoteIP string,
|
||||
password string,
|
||||
) *sshStageWrapper {
|
||||
return &sshStageWrapper{
|
||||
sshStage: stage,
|
||||
remoteIP: remoteIP,
|
||||
password: password,
|
||||
}
|
||||
}
|
||||
|
||||
func (sw *sshStageWrapper) Do(ctx context.Context, args interface{}) error {
|
||||
cli, err := ssh.NewClient(sw.remoteIP, 22, "root", sw.password, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sw.sshStage(ctx, cli, args)
|
||||
}
|
||||
|
||||
type ITask interface {
|
||||
// GetStage return current task stage func
|
||||
GetStage() TaskStageFunc
|
||||
// SetStage set task next execute stage func
|
||||
SetStage(stage TaskStageFunc)
|
||||
|
||||
// GetSSHStage return current task ssh stage func
|
||||
GetSSHStage() SSHTaskStageFunc
|
||||
// SetSSHStage set task next execute ssh stage func
|
||||
SetSSHStage(stage SSHTaskStageFunc)
|
||||
|
||||
// GetTaskId return remote service task id
|
||||
GetTaskId() string
|
||||
|
||||
GetTaskQueue() *TaskQueue
|
||||
// GetData return TaskData from region
|
||||
GetData() jsonutils.JSONObject
|
||||
GetName() string
|
||||
|
||||
Execute(ITask ITask, args interface{})
|
||||
SSHExecute(task ITask, remoteIP string, passwd string, args interface{})
|
||||
}
|
||||
|
||||
func NewTaskQueue() *TaskQueue {
|
||||
return &TaskQueue{
|
||||
Queue: NewQueue(),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *TaskQueue) GetTask() ITask {
|
||||
if q.IsEmpty() {
|
||||
return nil
|
||||
}
|
||||
return q.First().(ITask)
|
||||
}
|
||||
|
||||
func (q *TaskQueue) PopTask() ITask {
|
||||
if q.IsEmpty() {
|
||||
return nil
|
||||
}
|
||||
return q.Pop().(ITask)
|
||||
}
|
||||
|
||||
func (q *TaskQueue) AppendTask(task ITask) *TaskQueue {
|
||||
log.Infof("Append task %s", task.GetName())
|
||||
q.Append(task)
|
||||
return q
|
||||
}
|
||||
|
||||
type IBaremetalTask interface {
|
||||
ITask
|
||||
NeedPXEBoot() bool
|
||||
}
|
||||
|
||||
type SBaremetalTaskBase struct {
|
||||
Baremetal IBaremetal
|
||||
stageFunc TaskStageFunc
|
||||
sshStageFunc SSHTaskStageFunc
|
||||
taskId string
|
||||
data jsonutils.JSONObject
|
||||
}
|
||||
|
||||
func newBaremetalTaskBase(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) *SBaremetalTaskBase {
|
||||
task := &SBaremetalTaskBase{
|
||||
Baremetal: baremetal,
|
||||
taskId: taskId,
|
||||
data: data,
|
||||
}
|
||||
return task
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetTaskQueue() *TaskQueue {
|
||||
return task.Baremetal.GetTaskQueue()
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetTaskId() string {
|
||||
return task.taskId
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetData() jsonutils.JSONObject {
|
||||
return task.data
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetStage() TaskStageFunc {
|
||||
return task.stageFunc
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetSSHStage() SSHTaskStageFunc {
|
||||
return task.sshStageFunc
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) SetStage(stage TaskStageFunc) {
|
||||
task.stageFunc = stage
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) SetSSHStage(stage SSHTaskStageFunc) {
|
||||
task.sshStageFunc = stage
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) Execute(iTask ITask, args interface{}) {
|
||||
ExecuteTask(iTask, args)
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) SSHExecute(
|
||||
iTask ITask,
|
||||
remoteIP string,
|
||||
password string,
|
||||
args interface{},
|
||||
) {
|
||||
iTask.SetStage(sshStageW(iTask.GetSSHStage(), remoteIP, password).Do)
|
||||
ExecuteTask(iTask, args)
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) CallNextStage(iTask ITask, stage TaskStageFunc, args interface{}) {
|
||||
iTask.SetStage(stage)
|
||||
ExecuteTask(iTask, args)
|
||||
}
|
||||
|
||||
type IPXEBootTask interface {
|
||||
ITask
|
||||
OnPXEBoot(ctx context.Context, args interface{}) error
|
||||
}
|
||||
|
||||
type SBaremetalPXEBootTaskBase struct {
|
||||
*SBaremetalTaskBase
|
||||
}
|
||||
|
||||
func newBaremetalPXEBootTaskBase(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
pxeBootTask IPXEBootTask,
|
||||
) *SBaremetalPXEBootTaskBase {
|
||||
baseTask := newBaremetalTaskBase(baremetal, taskId, data)
|
||||
self := &SBaremetalPXEBootTaskBase{
|
||||
SBaremetalTaskBase: baseTask,
|
||||
}
|
||||
//OnInitStage(pxeBootTask)
|
||||
sshConf, _ := self.Baremetal.GetSSHConfig()
|
||||
if sshConf != nil && self.Baremetal.TestSSHConfig() {
|
||||
pxeBootTask.SetStage(pxeBootTask.OnPXEBoot)
|
||||
return self
|
||||
}
|
||||
// Do soft reboot
|
||||
if data != nil && jsonutils.QueryBoolean(data, "soft_boot", false) {
|
||||
//self.SetStage(self.WaitForShutdown)
|
||||
// self.start_time = time.time()
|
||||
self.Baremetal.DoPowerShutdown(true)
|
||||
self.CallNextStage(self, self.WaitForShutdown, nil)
|
||||
return self
|
||||
}
|
||||
// shutdown and power up to PXE mode
|
||||
self.EnsurePowerShutdown(false)
|
||||
self.EnsurePowerUp("pxe")
|
||||
// this stage will be called by baremetalInstance when pxe start
|
||||
self.SetStage(pxeBootTask.OnPXEBoot)
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) WaitForShutdown(ctx context.Context, args interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) GetName() string {
|
||||
return "BaremetalPXEBootTaskBase"
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) EnsurePowerShutdown(soft bool) {
|
||||
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) EnsurePowerUp(bootdev string) {
|
||||
log.Infof("[EnsurePowerUp] bootdev: %s", bootdev)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQueue(t *testing.T) {
|
||||
type test struct {
|
||||
queue *Queue
|
||||
expected string
|
||||
}
|
||||
q123 := NewQueue().Append("1").Append("2").Append("3")
|
||||
q123Pop := NewQueue().Append("1").Append("2").Append("3")
|
||||
q123Pop.Pop()
|
||||
qEmptyPop := NewQueue().Append("1").Append("2")
|
||||
qEmptyPop.Pop()
|
||||
qEmptyPop.Pop()
|
||||
qEmptyPop.Pop()
|
||||
tests := map[string]test{
|
||||
"Empty queue": {
|
||||
queue: NewQueue(),
|
||||
expected: "[]",
|
||||
},
|
||||
"Queue append": {
|
||||
queue: q123,
|
||||
expected: "[1 2 3]",
|
||||
},
|
||||
"Queue pop": {
|
||||
queue: q123Pop,
|
||||
expected: "[2 3]",
|
||||
},
|
||||
"Queue pop to empty": {
|
||||
queue: qEmptyPop,
|
||||
expected: "[]",
|
||||
},
|
||||
}
|
||||
for name, testCase := range tests {
|
||||
output := testCase.queue.String()
|
||||
expected := testCase.expected
|
||||
if output != expected {
|
||||
t.Errorf("TestCase %q failed, output: %v, expected: %v", name, output, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
type SBaremetalServerBaseDeployTask struct {
|
||||
*SBaremetalPXEBootTaskBase
|
||||
}
|
||||
|
||||
func newBaremetalServerBaseDeployTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
queue *TaskQueue,
|
||||
) *SBaremetalServerBaseDeployTask {
|
||||
task := new(SBaremetalServerBaseDeployTask)
|
||||
baseTask := newBaremetalPXEBootTaskBase(baremetal, taskId, data, task)
|
||||
task.SBaremetalPXEBootTaskBase = baseTask
|
||||
return task
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerBaseDeployTask) GetName() string {
|
||||
return "BaremetalServerBaseDeployTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerBaseDeployTask) OnPXEBoot(ctx context.Context, args interface{}) error {
|
||||
log.Infof("%s called on stage pxeboot, args: %v", self.GetName(), args)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/sysutils"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type sBaremetalPrepareTask struct {
|
||||
baremetal IBaremetal
|
||||
}
|
||||
|
||||
func newBaremetalPrepareTask(baremetal IBaremetal) *sBaremetalPrepareTask {
|
||||
return &sBaremetalPrepareTask{
|
||||
baremetal: baremetal,
|
||||
}
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
|
||||
_, err := cli.Run("/lib/mos/sysinit.sh")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sysInfo, err := getDMISysinfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cpuInfo, err := getCPUInfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dmiCPUInfo, err := getDMICPUInfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
memInfo, err := getDMIMemInfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nicsInfo, err := getNicsInfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: diskinfo
|
||||
|
||||
ipmiEnable, err := isIPMIEnable(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ipmiEnable {
|
||||
log.Errorf("TODO: ipmi enable")
|
||||
}
|
||||
|
||||
adminNic := task.baremetal.GetAdminNic()
|
||||
|
||||
// collect params
|
||||
updateInfo := make(map[string]interface{})
|
||||
oname := fmt.Sprintf("BM%s", strings.Replace(adminNic.Mac, ":", "", -1))
|
||||
if task.baremetal.GetName() == oname {
|
||||
//updateInfo["name"] = fmt.Sprintf("BM-%s", strings.Replace(ipmiInfo.IPAddr, ".", "-", -1))
|
||||
}
|
||||
updateInfo["access_ip"] = adminNic.IpAddr
|
||||
updateInfo["cpu_count"] = cpuInfo.Count
|
||||
updateInfo["node_count"] = dmiCPUInfo.Nodes
|
||||
updateInfo["cpu_desc"] = cpuInfo.Model
|
||||
updateInfo["cpu_mhz"] = cpuInfo.Freq
|
||||
updateInfo["cpu_cache"] = cpuInfo.Cache
|
||||
updateInfo["sys_info"] = sysInfo
|
||||
updateInfo["sn"] = sysInfo.SN
|
||||
|
||||
log.Infof("Parse DMI info: %#v, \ncpuInfo: %#v", sysInfo, cpuInfo)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDMISysinfo(cli *ssh.Client) (*types.DMIInfo, error) {
|
||||
ret, err := cli.Run("/usr/sbin/dmidecode -t 1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sysutils.ParseDMISysinfo(ret)
|
||||
}
|
||||
|
||||
func getCPUInfo(cli *ssh.Client) (*types.CPUInfo, error) {
|
||||
ret, err := cli.Run("cat /proc/cpuinfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sysutils.ParseCPUInfo(ret)
|
||||
}
|
||||
|
||||
func getDMICPUInfo(cli *ssh.Client) (*types.DMICPUInfo, error) {
|
||||
ret, err := cli.Run("/usr/sbin/dmidecode -t 4")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sysutils.ParseDMICPUInfo(ret), nil
|
||||
}
|
||||
|
||||
func getDMIMemInfo(cli *ssh.Client) (*types.DMIMemInfo, error) {
|
||||
ret, err := cli.Run("/usr/sbin/dmidecode -t 4")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sysutils.ParseDMIMemInfo(ret), nil
|
||||
}
|
||||
|
||||
func getNicsInfo(cli *ssh.Client) ([]*types.NicDevInfo, error) {
|
||||
ret, err := cli.Run("/lib/mos/lsnic")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to retrieve NIC info: %v", err)
|
||||
}
|
||||
return sysutils.ParseNicInfo(ret), nil
|
||||
}
|
||||
|
||||
func isIPMIEnable(cli *ssh.Client) (bool, error) {
|
||||
ret, err := cli.Run("/usr/sbin/dmidecode -t 38")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to retrieve IPMI info: %v", err)
|
||||
}
|
||||
return sysutils.ParseDMIIPMIInfo(ret), nil
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
)
|
||||
|
||||
type IBaremetal interface {
|
||||
GetTaskQueue() *TaskQueue
|
||||
GetSSHConfig() (*types.SSHConfig, error)
|
||||
TestSSHConfig() bool
|
||||
DoPowerShutdown(soft bool)
|
||||
GetAdminNic() *types.Nic
|
||||
GetName() string
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalServerPrepareTask struct {
|
||||
*SBaremetalTaskBase
|
||||
}
|
||||
|
||||
func NewBaremetalServerPrepareTask(
|
||||
baremetal IBaremetal,
|
||||
) *SBaremetalServerPrepareTask {
|
||||
baseTask := newBaremetalTaskBase(baremetal, "", nil)
|
||||
task := &SBaremetalServerPrepareTask{
|
||||
SBaremetalTaskBase: baseTask,
|
||||
}
|
||||
task.SetSSHStage(task.OnPXEBootRequest)
|
||||
return task
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerPrepareTask) GetName() string {
|
||||
return "BaremetalServerPrepareTask"
|
||||
}
|
||||
|
||||
// OnPXEBootRequest called by notify api handler
|
||||
func (self *SBaremetalServerPrepareTask) OnPXEBootRequest(ctx context.Context, cli *ssh.Client, args interface{}) error {
|
||||
err := newBaremetalPrepareTask(self.Baremetal).DoPrepare(cli)
|
||||
if err != nil {
|
||||
log.Errorf("Prepare failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
)
|
||||
|
||||
var baremetalTaskWorkerMan *appsrv.SWorkerManager
|
||||
|
||||
func init() {
|
||||
baremetalTaskWorkerMan = appsrv.NewWorkerManager("BaremetalTaskWorkerManager", 8, 1024)
|
||||
}
|
||||
|
||||
func ExecuteTask(task ITask, args interface{}) {
|
||||
baremetalTaskWorkerMan.Run(func() {
|
||||
executeTask(task, args)
|
||||
}, nil, nil)
|
||||
}
|
||||
|
||||
func executeTask(task ITask, args interface{}) {
|
||||
if task == nil {
|
||||
return
|
||||
}
|
||||
curStage := task.GetStage()
|
||||
if curStage == nil {
|
||||
return
|
||||
}
|
||||
err := curStage(context.Background(), args)
|
||||
if err != nil {
|
||||
log.Errorf("Execute task %s error: %v", task.GetName(), err)
|
||||
SetTaskFail(task, err)
|
||||
}
|
||||
}
|
||||
|
||||
func SetTaskComplete(task ITask) {
|
||||
taskId := task.GetTaskId()
|
||||
if taskId != "" {
|
||||
// TODO: notify region complete
|
||||
}
|
||||
onTaskEnd(task)
|
||||
}
|
||||
|
||||
func SetTaskFail(task ITask, err error) {
|
||||
taskId := task.GetTaskId()
|
||||
if taskId != "" {
|
||||
// TODO: notify region task fail
|
||||
}
|
||||
onTaskEnd(task)
|
||||
}
|
||||
|
||||
func onTaskEnd(task ITask) {
|
||||
task.SetStage(nil)
|
||||
ExecuteTask(task.GetTaskQueue().PopTask(), nil)
|
||||
}
|
||||
|
||||
func OnInitStage(task ITask) error {
|
||||
log.Infof("Start task %s", task.GetName())
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package types
|
||||
@@ -0,0 +1,9 @@
|
||||
package types
|
||||
|
||||
type IPMIInfo struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
IpAddr string `json:"ip_addr"`
|
||||
Present bool `json:"present"`
|
||||
LanChannel int `json:"lan_channel"`
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package types
|
||||
|
||||
type SSHConfig struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
RemoteIP string `json:"ip"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type DMIInfo struct {
|
||||
Manufacture string `json:"manufacture"`
|
||||
Model string `json:"model"`
|
||||
Version string `json:"version,omitempty"`
|
||||
SN string `json:"sn"`
|
||||
}
|
||||
|
||||
type CPUInfo struct {
|
||||
Count int `json:"count"`
|
||||
Model string `json:"desc"`
|
||||
Freq int `json:"freq"`
|
||||
Cache int `json:"cache"`
|
||||
}
|
||||
|
||||
type DMICPUInfo struct {
|
||||
Nodes int `json:"nodes"`
|
||||
}
|
||||
|
||||
type DMIMemInfo struct {
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
type NicDevInfo struct {
|
||||
Dev string `json:"dev"`
|
||||
Mac string `json:"mac"`
|
||||
Speed int `json:"speed"`
|
||||
Up bool `json:"up"`
|
||||
Mtu int `json:"mtu"`
|
||||
}
|
||||
|
||||
type DiskInfo struct {
|
||||
Dev string `json:"dev"`
|
||||
Sector int `json:"sector"`
|
||||
Block int `json:"block"`
|
||||
Size int `json:"size"`
|
||||
Rotate bool `json:"rotate"`
|
||||
ModuleInfo string `json:"module"`
|
||||
Kernel string `json:"kernel"`
|
||||
PCIClass string `json:"pci_class"`
|
||||
Driver string `json:"driver"`
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package detect_storages
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
func DetectStorageInfo(cli *ssh.Client, wait bool) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dhcp4
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/ipv4"
|
||||
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
// defined as a var so tests can override it.
|
||||
@@ -141,14 +143,17 @@ func (c *Conn) RecvDHCP() (*Packet, *net.Interface, error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
if c.ifIndex != 0 && ifidx != c.ifIndex {
|
||||
log.Errorf("======= ifIndex continue, c.ifIndex: %d, ifidx: %d", c.ifIndex, ifidx)
|
||||
continue
|
||||
}
|
||||
pkt, err := Unmarshal(b)
|
||||
if err != nil {
|
||||
log.Errorf("======= pkt Unmarshal error: %v", err)
|
||||
continue
|
||||
}
|
||||
intf, err := net.InterfaceByIndex(ifidx)
|
||||
if err != nil {
|
||||
log.Errorf("======= intf error: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -178,7 +183,7 @@ func (c *Conn) SendDHCP(pkt *Packet, intf *net.Interface) error {
|
||||
case txRelayAddr:
|
||||
addr := net.UDPAddr{
|
||||
IP: pkt.RelayAddr,
|
||||
Port: 67,
|
||||
Port: dhcpClientPort,
|
||||
}
|
||||
return c.conn.Send(b, &addr, 0)
|
||||
case txClientAddr:
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
//+build linux
|
||||
|
||||
package dhcp4
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2016 Google Inc.
|
||||
//
|
||||
// Licensed 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 linux
|
||||
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLinuxConn(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skipf("not supported on %s", runtime.GOOS)
|
||||
}
|
||||
if os.Getuid() != 0 {
|
||||
t.Skipf("must be root on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
// Use a listener to grab a free port, but we don't use it beyond
|
||||
// that.
|
||||
l, err := net.ListenPacket("udp4", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c, err := newLinuxConn(l.LocalAddr().(*net.UDPAddr).Port)
|
||||
if err != nil {
|
||||
t.Fatalf("creating the linuxconn: %s", err)
|
||||
}
|
||||
|
||||
testConn(t, c, l.LocalAddr().String())
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright 2016 Google Inc.
|
||||
//
|
||||
// Licensed 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 dhcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testConn(t *testing.T, impl conn, addr string) {
|
||||
c := &Conn{impl, 0}
|
||||
|
||||
s, err := net.Dial("udp4", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mac, err := net.ParseMAC("ce:e7:7b:ef:45:f7")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p := &Packet{
|
||||
Type: MsgDiscover,
|
||||
TransactionID: []byte("1234"),
|
||||
Broadcast: true,
|
||||
HardwareAddr: mac,
|
||||
}
|
||||
bs, err := p.Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("marshaling packet: %s", err)
|
||||
}
|
||||
// Unmarshal the packet again, to smooth out representation
|
||||
// differences (e.g. nil IP vs. IP set to 0.0.0.0).
|
||||
p, err = Unmarshal(bs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
s.Write(bs)
|
||||
}()
|
||||
if err = c.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rpkt, intf, err := c.RecvDHCP()
|
||||
if err != nil {
|
||||
t.Fatalf("reading DHCP packet: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(p, rpkt) {
|
||||
t.Fatalf("DHCP packet not the same as when it was sent")
|
||||
}
|
||||
|
||||
// Test writing
|
||||
p.ClientAddr = net.IPv4(127, 0, 0, 1)
|
||||
dhcpClientPort = s.LocalAddr().(*net.UDPAddr).Port
|
||||
bs2, err := p.Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("marshaling packet: %s", err)
|
||||
}
|
||||
// Unmarshal the packet again, to smooth out representation
|
||||
// differences (e.g. nil IP vs. IP set to 0.0.0.0).
|
||||
p, err = Unmarshal(bs2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() { dhcpClientPort = 68 }()
|
||||
|
||||
ch := make(chan *Packet, 1)
|
||||
go func() {
|
||||
s.SetReadDeadline(time.Now().Add(time.Second))
|
||||
var buf [1500]byte
|
||||
n, err := s.Read(buf[:])
|
||||
if err != nil {
|
||||
t.Errorf("reading DHCP packet sent by conn_linux: %s", err)
|
||||
ch <- nil
|
||||
return
|
||||
}
|
||||
pkt, err := Unmarshal(buf[:n])
|
||||
if err != nil {
|
||||
t.Errorf("decoding DHCP packet: %s", err)
|
||||
ch <- nil
|
||||
return
|
||||
}
|
||||
ch <- pkt
|
||||
}()
|
||||
|
||||
if err = c.SendDHCP(p, intf); err != nil {
|
||||
t.Fatalf("sending DHCP packet: %s", err)
|
||||
}
|
||||
|
||||
rpkt = <-ch
|
||||
if rpkt == nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if !reflect.DeepEqual(p, rpkt) {
|
||||
t.Fatalf("DHCP packet not the same as when it was sent")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPortableConn(t *testing.T) {
|
||||
// Use a listener to grab a free port, but we don't use it beyond
|
||||
// that.
|
||||
l, err := net.ListenPacket("udp4", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port := l.LocalAddr().(*net.UDPAddr).Port
|
||||
addr := l.LocalAddr().String()
|
||||
l.Close()
|
||||
|
||||
c, err := newPortableConn(port)
|
||||
if err != nil {
|
||||
t.Fatalf("creating the conn: %s", err)
|
||||
}
|
||||
|
||||
testConn(t, c, addr)
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
//+build !linux
|
||||
|
||||
package dhcp4
|
||||
package dhcp
|
||||
|
||||
import "errors"
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package dhcp4 provides building blocks for DHCP clients and servers.
|
||||
package dhcp4 // import "go.universe.tf/netboot/dhcp4"
|
||||
// Package dhcp provides building blocks for DHCP clients and servers.
|
||||
package dhcp // import "yunion.io/x/onecloud/pkg/cloudcommon/dhcp"
|
||||
@@ -0,0 +1,144 @@
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
const (
|
||||
PXECLIENT = "PXEClient"
|
||||
)
|
||||
|
||||
type ResponseConfig struct {
|
||||
OsName string
|
||||
ServerIP net.IP // OptServerIdentifier 54
|
||||
ClientIP net.IP
|
||||
Gateway net.IP // OptRouters 3
|
||||
Domain string // OptDomainName 15
|
||||
LeaseTime time.Duration // OptLeaseTime 51
|
||||
RenewalTime time.Duration // OptRenewalTime 58
|
||||
BroadcastAddr net.IP // OptBroadcastAddr 28
|
||||
Hostname string // OptHostname 12
|
||||
SubnetMask net.IP // OptSubnetMask 1
|
||||
DNSServer net.IP // OptDNSServers
|
||||
Routes interface{} // TODO: 249 for windows, 121 for linux
|
||||
|
||||
// TFTP config
|
||||
BootServer string
|
||||
BootFile string
|
||||
}
|
||||
|
||||
func (conf ResponseConfig) GetHostname() string {
|
||||
hostname := conf.Hostname
|
||||
if conf.Domain != "" {
|
||||
hostname = fmt.Sprintf("%s.%s", hostname, conf.Domain)
|
||||
}
|
||||
return hostname
|
||||
}
|
||||
|
||||
func GetOptIP(ip net.IP) []byte {
|
||||
return []byte(ip.To4())
|
||||
}
|
||||
|
||||
func GetOptTime(d time.Duration) []byte {
|
||||
timeBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(timeBytes, uint32(d/time.Second))
|
||||
return timeBytes
|
||||
}
|
||||
|
||||
func MakeReplyPacket(pkt *Packet, conf *ResponseConfig) (*Packet, error) {
|
||||
msgType := MsgOffer
|
||||
if pkt.Type == MsgRequest {
|
||||
reqAddr, _ := pkt.Options.IP(OptRequestedIP)
|
||||
if reqAddr != nil && !conf.ClientIP.Equal(reqAddr) {
|
||||
msgType = MsgNack
|
||||
} else {
|
||||
msgType = MsgAck
|
||||
}
|
||||
}
|
||||
return makeDHCPReplyPacket(pkt, conf, msgType), nil
|
||||
}
|
||||
|
||||
func getPacketVendorClassId(pkt *Packet) string {
|
||||
vendorClsId, _ := pkt.Options.String(OptVendorIdentifier)
|
||||
return vendorClsId
|
||||
}
|
||||
|
||||
func makeDHCPReplyPacket(pkt *Packet, conf *ResponseConfig, msgType MessageType) *Packet {
|
||||
if conf.OsName == "" {
|
||||
if vendorClsId := getPacketVendorClassId(pkt); vendorClsId != "" && strings.HasPrefix(vendorClsId, "MSFT ") {
|
||||
conf.OsName = "win"
|
||||
}
|
||||
}
|
||||
resp := &Packet{
|
||||
Type: msgType,
|
||||
TransactionID: pkt.TransactionID,
|
||||
HardwareAddr: pkt.HardwareAddr,
|
||||
RelayAddr: pkt.RelayAddr,
|
||||
ClientAddr: pkt.ClientAddr,
|
||||
ServerAddr: conf.ServerIP,
|
||||
Options: make(Options),
|
||||
}
|
||||
if msgType == MsgNack {
|
||||
return resp
|
||||
}
|
||||
resp.YourAddr = conf.ClientIP
|
||||
resp.Options[OptServerIdentifier] = GetOptIP(conf.ServerIP)
|
||||
if conf.SubnetMask != nil {
|
||||
resp.Options[OptSubnetMask] = GetOptIP(conf.SubnetMask)
|
||||
}
|
||||
if conf.Gateway != nil {
|
||||
resp.Options[OptRouters] = GetOptIP(conf.Gateway)
|
||||
}
|
||||
if conf.Domain != "" {
|
||||
resp.Options[OptDomainName] = []byte(conf.Domain)
|
||||
}
|
||||
if conf.BroadcastAddr != nil {
|
||||
resp.Options[OptBroadcastAddr] = GetOptIP(conf.BroadcastAddr)
|
||||
}
|
||||
if conf.Hostname != "" {
|
||||
resp.Options[OptHostname] = []byte(conf.GetHostname())
|
||||
}
|
||||
if conf.DNSServer != nil {
|
||||
resp.Options[OptDNSServers] = GetOptIP(conf.DNSServer)
|
||||
}
|
||||
if conf.BootServer != "" {
|
||||
resp.BootServerName = conf.BootServer
|
||||
}
|
||||
if conf.BootFile != "" {
|
||||
resp.BootFilename = conf.BootFile
|
||||
// says the server should identify itself as a PXEClient vendor
|
||||
// type, even though it's a server. Strange.
|
||||
resp.Options[OptVendorIdentifier] = []byte(PXECLIENT)
|
||||
}
|
||||
if pkt.Options[OptClientMachineIdentifier] != nil {
|
||||
resp.Options[OptClientMachineIdentifier] = pkt.Options[OptClientMachineIdentifier]
|
||||
}
|
||||
if conf.LeaseTime > 0 {
|
||||
resp.Options[OptLeaseTime] = GetOptTime(conf.LeaseTime)
|
||||
}
|
||||
if conf.RenewalTime > 0 {
|
||||
resp.Options[OptRenewalTime] = GetOptTime(conf.RenewalTime)
|
||||
}
|
||||
|
||||
// TODO: routes support
|
||||
return resp
|
||||
}
|
||||
|
||||
func IsPXERequest(pkt *Packet) bool {
|
||||
if pkt.Type != MsgDiscover {
|
||||
log.Warningf("packet is %s, not %s", pkt.Type, MsgDiscover)
|
||||
return false
|
||||
}
|
||||
|
||||
if pkt.Options[OptClientArchitecture] == nil {
|
||||
log.Warningf("not a PXE boot request (missing option 93)")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dhcp4
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -62,6 +62,10 @@ const (
|
||||
OptTFTPServer Option = 66 // string
|
||||
OptBootFile Option = 67 // string
|
||||
OptDHCPMessageType Option = 53 // byte
|
||||
|
||||
OptClientArchitecture Option = 93
|
||||
OptClientNetworkInterfaceIdentifier Option = 94
|
||||
OptClientMachineIdentifier Option = 97
|
||||
)
|
||||
|
||||
// Options stores DHCP options.
|
||||
@@ -0,0 +1,198 @@
|
||||
// Copyright 2016 Google Inc.
|
||||
//
|
||||
// Licensed 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 dhcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOptionByte(t *testing.T) {
|
||||
o := Options{
|
||||
1: []byte{3},
|
||||
2: []byte{1, 2, 3},
|
||||
}
|
||||
|
||||
b, err := o.Byte(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b != 3 {
|
||||
t.Fatalf("wanted value 3, got %d", b)
|
||||
}
|
||||
|
||||
b, err = o.Byte(2)
|
||||
if err == nil {
|
||||
t.Fatalf("option shouldn't be a valid byte")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionUint16(t *testing.T) {
|
||||
o := Options{
|
||||
1: []byte{1, 2},
|
||||
2: []byte{1, 2, 3},
|
||||
}
|
||||
|
||||
u, err := o.Uint16(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if u != 258 {
|
||||
t.Fatalf("wanted value 258, got %d", u)
|
||||
}
|
||||
|
||||
u, err = o.Uint16(2)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid uint16")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionUint32(t *testing.T) {
|
||||
o := Options{
|
||||
1: []byte{1, 2, 3, 4},
|
||||
2: []byte{1, 2, 3},
|
||||
}
|
||||
|
||||
u, err := o.Uint32(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if u != 16909060 {
|
||||
t.Fatalf("wanted value 16909060, got %d", u)
|
||||
}
|
||||
|
||||
u, err = o.Uint32(2)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid uint32")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionInt32(t *testing.T) {
|
||||
o := Options{
|
||||
1: []byte{0xff, 0xff, 0xff, 0xff},
|
||||
2: []byte{1, 2, 3},
|
||||
}
|
||||
|
||||
u, err := o.Int32(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if u != -1 {
|
||||
t.Fatalf("wanted value -1, got %d", u)
|
||||
}
|
||||
|
||||
u, err = o.Int32(2)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid int32")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionIPs(t *testing.T) {
|
||||
o := Options{
|
||||
1: []byte{1, 2, 3, 4, 5, 6, 7, 8},
|
||||
2: []byte{1, 2, 3, 4, 5, 6},
|
||||
3: []byte{1, 2, 3},
|
||||
}
|
||||
|
||||
ips, err := o.IPs(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ips) != 2 {
|
||||
t.Fatal("wrong number of IPs")
|
||||
}
|
||||
if !ips[0].Equal(net.IPv4(1, 2, 3, 4)) {
|
||||
t.Fatalf("wrong first IP, got %s", ips[0])
|
||||
}
|
||||
if !ips[1].Equal(net.IPv4(5, 6, 7, 8)) {
|
||||
t.Fatalf("wrong second IP, got %s", ips[0])
|
||||
}
|
||||
|
||||
ips, err = o.IPs(2)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid IPs")
|
||||
}
|
||||
|
||||
ips, err = o.IPs(3)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid IPs")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionIP(t *testing.T) {
|
||||
o := Options{
|
||||
1: []byte{1, 2, 3, 4},
|
||||
2: []byte{1, 2, 3, 4, 5, 6},
|
||||
3: []byte{1, 2, 3},
|
||||
}
|
||||
|
||||
ip, err := o.IP(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !ip.Equal(net.IPv4(1, 2, 3, 4)) {
|
||||
t.Fatalf("wrong first IP, got %s", ip)
|
||||
}
|
||||
|
||||
ip, err = o.IP(2)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid IPs")
|
||||
}
|
||||
|
||||
ip, err = o.IP(3)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid IPs")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionIPMask(t *testing.T) {
|
||||
o := Options{
|
||||
1: []byte{1, 2, 3, 4},
|
||||
2: []byte{1, 2, 3, 4, 5, 6},
|
||||
3: []byte{1, 2, 3},
|
||||
}
|
||||
|
||||
ipmask, err := o.IPMask(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !net.IP(ipmask).Equal(net.IP(net.IPv4Mask(1, 2, 3, 4))) {
|
||||
t.Fatalf("wrong first IP, got %s", ipmask)
|
||||
}
|
||||
|
||||
ipmask, err = o.IPMask(2)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid IPs")
|
||||
}
|
||||
|
||||
ipmask, err = o.IPMask(3)
|
||||
if err == nil {
|
||||
t.Fatal("option shouldn't be a valid IPs")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
o := Options{
|
||||
1: []byte{2},
|
||||
2: []byte{3, 4},
|
||||
}
|
||||
|
||||
o2 := o.Copy()
|
||||
delete(o2, 2)
|
||||
|
||||
if len(o) != 2 {
|
||||
t.Fatalf("Mutating Option copy mutated the original")
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dhcp4
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -0,0 +1,63 @@
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
type DHCPServer struct {
|
||||
Address string
|
||||
Port int
|
||||
conn *Conn
|
||||
}
|
||||
|
||||
func NewDHCPServer(address string, port int) *DHCPServer {
|
||||
return &DHCPServer{
|
||||
Address: address,
|
||||
Port: port,
|
||||
}
|
||||
}
|
||||
|
||||
type DHCPHandler interface {
|
||||
ServeDHCP(pkt *Packet) (*Packet, error)
|
||||
}
|
||||
|
||||
func (s *DHCPServer) ListenAndServe(handler DHCPHandler) error {
|
||||
dhcpAddr := fmt.Sprintf("%s:%d", s.Address, s.Port)
|
||||
dhcpConn, err := NewConn(dhcpAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Listen DHCP connection error: %v", err)
|
||||
}
|
||||
s.conn = dhcpConn
|
||||
defer s.conn.Close()
|
||||
return s.serveDHCP(handler)
|
||||
}
|
||||
|
||||
func (s *DHCPServer) serveDHCP(handler DHCPHandler) error {
|
||||
for {
|
||||
pkt, intf, err := s.conn.RecvDHCP()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Receiving DHCP packet: %s", err)
|
||||
}
|
||||
if intf == nil {
|
||||
return fmt.Errorf("Received DHCP packet with no interface information (this is a violation of dhcp4.Conn's contract)")
|
||||
}
|
||||
go func() {
|
||||
resp, err := handler.ServeDHCP(pkt)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP] handler serve error: %v", err)
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
log.Warningf("[DHCP] hander response null packet")
|
||||
return
|
||||
}
|
||||
log.Debugf("[DHCP] send response packet: %s to interface: %#v", resp.DebugString(), intf)
|
||||
if err = s.conn.SendDHCP(resp, intf); err != nil {
|
||||
log.Errorf("[DHCP] failed to response packet for %s: %v", pkt.HardwareAddr, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
@@ -122,6 +122,7 @@ func (self *SCloudprovider) ValidateDeleteCondition(ctx context.Context) error {
|
||||
}
|
||||
usage := self.getUsage()
|
||||
if !usage.isEmpty() {
|
||||
log.Errorf("======Usage %#v", usage)
|
||||
return httperrors.NewNotEmptyError("Not an empty cloud provider")
|
||||
}
|
||||
return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
type ClientConfig struct {
|
||||
Username string
|
||||
Password string
|
||||
Host string
|
||||
Port int
|
||||
PrivateKey string
|
||||
}
|
||||
|
||||
func parsePrivateKey(keyBuff string) (ssh.Signer, error) {
|
||||
return ssh.ParsePrivateKey([]byte(keyBuff))
|
||||
}
|
||||
|
||||
func (conf ClientConfig) ToSshConfig() (*ssh.ClientConfig, error) {
|
||||
cliConfig := &ssh.ClientConfig{
|
||||
User: conf.Username,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
auths := make([]ssh.AuthMethod, 0)
|
||||
if conf.Password != "" {
|
||||
auths = append(auths, ssh.Password(conf.Password))
|
||||
}
|
||||
if conf.PrivateKey != "" {
|
||||
signer, err := parsePrivateKey(conf.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
auths = append(auths, ssh.PublicKeys(signer))
|
||||
}
|
||||
cliConfig.Auth = auths
|
||||
return cliConfig, nil
|
||||
}
|
||||
|
||||
func (conf ClientConfig) Connect() (*ssh.Client, error) {
|
||||
cliConfig, err := conf.ToSshConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
|
||||
client, err := ssh.Dial("tcp", addr, cliConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
client *ssh.Client
|
||||
}
|
||||
|
||||
func (conf ClientConfig) NewClient() (*Client, error) {
|
||||
cli, err := conf.Connect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Client{
|
||||
client: cli,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewClient(
|
||||
host string,
|
||||
port int,
|
||||
username string,
|
||||
password string,
|
||||
privateKey string,
|
||||
) (*Client, error) {
|
||||
config := &ClientConfig{
|
||||
Host: host,
|
||||
Port: port,
|
||||
Username: username,
|
||||
Password: password,
|
||||
PrivateKey: privateKey,
|
||||
}
|
||||
return config.NewClient()
|
||||
}
|
||||
|
||||
func (s *Client) Run(cmds ...string) ([]string, error) {
|
||||
ret := []string{}
|
||||
for _, cmd := range cmds {
|
||||
session, err := s.client.NewSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer session.Close()
|
||||
out, err := session.CombinedOutput(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("Error output: %s", string(out))
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, parseOutput(out)...)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func parseOutput(output []byte) []string {
|
||||
lines := strings.Split(string(output), "\n")
|
||||
return lines
|
||||
}
|
||||
|
||||
func (s *Client) Close() {
|
||||
s.client.Close()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
const (
|
||||
username = "root"
|
||||
host = "10.168.222.245"
|
||||
password = "123@openmag"
|
||||
)
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
client, err := NewClient(host, 22, username, password, "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
out, err := client.Run("ls", "uname -a", "date", "hostname")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
log.Infof("output: %#v", out)
|
||||
}
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed 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.
|
||||
-339
@@ -1,339 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -1,12 +0,0 @@
|
||||
In general iPXE files are licensed under the GPL. For historical
|
||||
reasons, individual files may contain their own licence declarations.
|
||||
Most builds of iPXE do not contain all iPXE code (in particular, most
|
||||
builds will include only one driver), and so the overall licence can
|
||||
vary depending on what target you are building.
|
||||
|
||||
The resultant applicable licence(s) for any particular build can be
|
||||
determined by using "make bin/xxxxxxx.yyy.licence"; for example:
|
||||
|
||||
make bin/rtl8139.rom.licence
|
||||
|
||||
to determine the resultant licence(s) for the build bin/rtl8139.rom
|
||||
@@ -1,339 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -1,59 +0,0 @@
|
||||
UNMODIFIED BINARY DISTRIBUTION LICENCE
|
||||
|
||||
|
||||
PREAMBLE
|
||||
|
||||
The GNU General Public License provides a legal guarantee that
|
||||
software covered by it remains free (in the sense of freedom, not
|
||||
price). It achieves this guarantee by imposing obligations on anyone
|
||||
who chooses to distribute the software.
|
||||
|
||||
Some of these obligations may be seen as unnecessarily burdensome. In
|
||||
particular, when the source code for the software is already publicly
|
||||
and freely available, there is minimal value in imposing upon each
|
||||
distributor the obligation to provide the complete source code (or an
|
||||
equivalent written offer to provide the complete source code).
|
||||
|
||||
This Licence allows for the distribution of unmodified binaries built
|
||||
from publicly available source code, without imposing the obligations
|
||||
of the GNU General Public License upon anyone who chooses to
|
||||
distribute only the unmodified binaries built from that source code.
|
||||
|
||||
The extra permissions granted by this Licence apply only to unmodified
|
||||
binaries built from source code which has already been made available
|
||||
to the public in accordance with the terms of the GNU General Public
|
||||
Licence. Nothing in this Licence allows for the creation of
|
||||
closed-source modified versions of the Program. Any modified versions
|
||||
of the Program are subject to the usual terms and conditions of the
|
||||
GNU General Public License.
|
||||
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
This Licence applies to any Program or other work which contains a
|
||||
notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this Unmodified Binary Distribution Licence. All
|
||||
terms used in the text of this Licence are to be interpreted as they
|
||||
are used in version 2 of the GNU General Public License as published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If you have made this Program available to the public in both source
|
||||
code and executable form in accordance with the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later
|
||||
version, then you are hereby granted an additional permission to use,
|
||||
copy, and distribute the unmodified executable form of this Program
|
||||
(the "Unmodified Binary") without restriction, including the right to
|
||||
permit persons to whom the Unmodified Binary is furnished to do
|
||||
likewise, subject to the following conditions:
|
||||
|
||||
- when started running, the Program must display an announcement which
|
||||
includes the details of your existing publication of the Program
|
||||
made in accordance with the terms of the GNU General Public License.
|
||||
For example, the Program could display the URL of the publicly
|
||||
available source code from which the Unmodified Binary was built.
|
||||
|
||||
- when exercising your right to grant permissions under this Licence,
|
||||
you do not need to refer directly to the text of this Licence, but
|
||||
you may not grant permissions beyond those granted to you by this
|
||||
Licence.
|
||||
@@ -1,40 +0,0 @@
|
||||
The EFI headers contained herein are copied from the EFI Development
|
||||
Kit, available from http://www.tianocore.org and published under the
|
||||
following licence:
|
||||
|
||||
BSD License from Intel
|
||||
Copyright (c) 2004, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither the name of the Intel Corporation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
This licence applies only to files that are part of the EFI
|
||||
Development Kit. Other files may contain their own licence terms, or
|
||||
may fall under the standard iPXE GPL licence.
|
||||
@@ -1,163 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
|
||||
# List of licences we can handle
|
||||
my $known_licences = {
|
||||
gpl_any => {
|
||||
desc => "GPL (any version)",
|
||||
can_subsume => {
|
||||
public_domain => 1,
|
||||
bsd3 => 1,
|
||||
bsd2 => 1,
|
||||
mit => 1,
|
||||
isc => 1,
|
||||
},
|
||||
},
|
||||
gpl2_or_later => {
|
||||
desc => "GPL version 2 (or, at your option, any later version)",
|
||||
can_subsume => {
|
||||
gpl_any => 1,
|
||||
gpl2_or_later_or_ubdl => 1,
|
||||
public_domain => 1,
|
||||
bsd3 => 1,
|
||||
bsd2 => 1,
|
||||
mit => 1,
|
||||
isc => 1,
|
||||
},
|
||||
},
|
||||
gpl2_only => {
|
||||
desc => "GPL version 2 only",
|
||||
can_subsume => {
|
||||
gpl_any => 1,
|
||||
gpl2_or_later => 1,
|
||||
gpl2_or_later_or_ubdl => 1,
|
||||
public_domain => 1,
|
||||
bsd3 => 1,
|
||||
bsd2 => 1,
|
||||
mit => 1,
|
||||
isc => 1,
|
||||
},
|
||||
},
|
||||
gpl2_or_later_or_ubdl => {
|
||||
desc => ( "GPL version 2 (or, at your option, any later version) or ".
|
||||
"Unmodified Binary Distribution Licence" ),
|
||||
can_subsume => {
|
||||
public_domain => 1,
|
||||
bsd3 => 1,
|
||||
bsd2 => 1,
|
||||
mit => 1,
|
||||
isc => 1,
|
||||
},
|
||||
},
|
||||
public_domain => {
|
||||
desc => "Public Domain",
|
||||
can_subsume => {},
|
||||
},
|
||||
bsd4 => {
|
||||
desc => "BSD Licence (with advertising clause)",
|
||||
can_subsume => {
|
||||
public_domain => 1,
|
||||
bsd3 => 1,
|
||||
bsd2 => 1,
|
||||
mit => 1,
|
||||
isc => 1,
|
||||
},
|
||||
},
|
||||
bsd3 => {
|
||||
desc => "BSD Licence (without advertising clause)",
|
||||
can_subsume => {
|
||||
public_domain => 1,
|
||||
bsd2 => 1,
|
||||
mit => 1,
|
||||
isc => 1,
|
||||
},
|
||||
},
|
||||
bsd2 => {
|
||||
desc => "BSD Licence (without advertising or endorsement clauses)",
|
||||
can_subsume => {
|
||||
public_domain => 1,
|
||||
mit => 1,
|
||||
isc => 1,
|
||||
},
|
||||
},
|
||||
mit => {
|
||||
desc => "MIT/X11/Xorg Licence",
|
||||
can_subsume => {
|
||||
public_domain => 1,
|
||||
isc => 1,
|
||||
},
|
||||
},
|
||||
isc => {
|
||||
desc => "ISC Licence",
|
||||
can_subsume => {
|
||||
public_domain => 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
# Parse command-line options
|
||||
my $verbosity = 1;
|
||||
Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
|
||||
GetOptions (
|
||||
'verbose|v+' => sub { $verbosity++; },
|
||||
'quiet|q+' => sub { $verbosity--; },
|
||||
) or die "Could not parse command-line options\n";
|
||||
|
||||
# Parse licence list from command line
|
||||
my $licences = {};
|
||||
foreach my $licence ( @ARGV ) {
|
||||
die "Unknown licence \"$licence\"\n"
|
||||
unless exists $known_licences->{$licence};
|
||||
$licences->{$licence} = $known_licences->{$licence};
|
||||
}
|
||||
die "No licences specified\n" unless %$licences;
|
||||
|
||||
# Dump licence list
|
||||
if ( $verbosity >= 1 ) {
|
||||
print "The following licences appear within this file:\n";
|
||||
foreach my $licence ( keys %$licences ) {
|
||||
print " ".$licences->{$licence}->{desc}."\n"
|
||||
}
|
||||
}
|
||||
|
||||
# Apply licence compatibilities to reduce to a single resulting licence
|
||||
foreach my $licence ( keys %$licences ) {
|
||||
# Skip already-deleted licences
|
||||
next unless exists $licences->{$licence};
|
||||
# Subsume any subsumable licences
|
||||
foreach my $can_subsume ( keys %{$licences->{$licence}->{can_subsume}} ) {
|
||||
if ( exists $licences->{$can_subsume} ) {
|
||||
print $licences->{$licence}->{desc}." subsumes ".
|
||||
$licences->{$can_subsume}->{desc}."\n"
|
||||
if $verbosity >= 1;
|
||||
delete $licences->{$can_subsume};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Print resulting licence
|
||||
die "Cannot reduce to a single resulting licence!\n"
|
||||
if ( keys %$licences ) != 1;
|
||||
( my $licence ) = keys %$licences;
|
||||
print "The overall licence for this file is:\n " if $verbosity >= 1;
|
||||
print $licences->{$licence}->{desc}."\n";
|
||||
Reference in New Issue
Block a user