agent.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package baremetal
  15. import (
  16. "context"
  17. "fmt"
  18. "net"
  19. "net/http"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/util/httputils"
  22. "yunion.io/x/onecloud/pkg/appsrv"
  23. o "yunion.io/x/onecloud/pkg/baremetal/options"
  24. "yunion.io/x/onecloud/pkg/baremetal/pxe"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/agent"
  26. "yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
  27. "yunion.io/x/onecloud/pkg/mcclient"
  28. "yunion.io/x/onecloud/pkg/mcclient/auth"
  29. "yunion.io/x/onecloud/pkg/util/procutils"
  30. )
  31. const (
  32. AGENT_TYPE_BAREMETAL = "baremetal"
  33. )
  34. var (
  35. baremetalAgent *SBaremetalAgent
  36. )
  37. // BaremetalAgent has two types of address
  38. // - AccessAddress/Address: this is the address controller to accesss the agent
  39. // - ListenAddress: this is the address baremetal to access the agent
  40. type SBaremetalAgent struct {
  41. agent.SBaseAgent
  42. PXEServer *pxe.Server
  43. Manager *SBaremetalManager
  44. }
  45. func newBaremetalAgent() (*SBaremetalAgent, error) {
  46. agent := &SBaremetalAgent{}
  47. err := agent.Init(agent, o.Options.ListenInterface, o.Options.CachePath)
  48. if err != nil {
  49. return nil, err
  50. }
  51. // set guest fs NetDevPrefix
  52. fsdriver.NetDevPrefix = fsdriver.NetDevPrefixEN
  53. return agent, nil
  54. }
  55. func (agent *SBaremetalAgent) GetAgentType() string {
  56. return AGENT_TYPE_BAREMETAL
  57. }
  58. func (agent *SBaremetalAgent) GetPort() int {
  59. return o.Options.Port
  60. }
  61. func (agent *SBaremetalAgent) GetEnableSsl() bool {
  62. return o.Options.EnableSsl
  63. }
  64. func (agent *SBaremetalAgent) GetZoneId() string {
  65. return o.Options.Zone
  66. }
  67. func (agent *SBaremetalAgent) GetAdminSession() *mcclient.ClientSession {
  68. return auth.GetAdminSession(context.TODO(), o.Options.Region)
  69. }
  70. func (agent *SBaremetalAgent) GetPublicAdminSession() *mcclient.ClientSession {
  71. return auth.GetAdminSessionWithPublic(context.TODO(), o.Options.Region)
  72. }
  73. func (agent *SBaremetalAgent) GetListenIP() (net.IP, error) {
  74. return agent.FindListenIP(o.Options.ListenAddress)
  75. }
  76. func (agent *SBaremetalAgent) GetDHCPServerListenIP() (net.IP, error) {
  77. ips := agent.GetListenIPs()
  78. // baremetal dhcp server can't bind address 0.0.0.0:67, conflict with host agent
  79. // but can bind specific ip address, because socket set reuseaddr option
  80. if o.Options.ListenAddress == "" || o.Options.ListenAddress == "0.0.0.0" {
  81. return ips[0], nil
  82. }
  83. for _, ip := range ips {
  84. if ip.String() == o.Options.ListenAddress {
  85. return ip, nil
  86. }
  87. }
  88. return nil, fmt.Errorf("Not found ListenAddress %s on %s", o.Options.ListenAddress, o.Options.ListenInterface)
  89. }
  90. func (agent *SBaremetalAgent) GetAccessIP() (net.IP, error) {
  91. if o.Options.AccessAddress != "" && o.Options.AccessAddress != "0.0.0.0" {
  92. return net.ParseIP(o.Options.AccessAddress), nil
  93. }
  94. if o.Options.Address != "" && o.Options.Address != "0.0.0.0" {
  95. return net.ParseIP(o.Options.Address), nil
  96. }
  97. return agent.FindAccessIP(o.Options.AccessAddress)
  98. }
  99. func (agent *SBaremetalAgent) GetDHCPServerIP() (net.IP, error) {
  100. listenIP := o.Options.ListenAddress
  101. if len(listenIP) == 0 || listenIP == "0.0.0.0" {
  102. return agent.GetAccessIP()
  103. }
  104. return agent.GetListenIP()
  105. }
  106. func (agent *SBaremetalAgent) StartService() error {
  107. manager, err := NewBaremetalManager(agent)
  108. if err != nil {
  109. return fmt.Errorf("New baremetal manager error: %v", err)
  110. }
  111. files, err := manager.loadConfigs()
  112. if err != nil {
  113. return fmt.Errorf("Baremetal manager load config error: %v", err)
  114. }
  115. ctx := context.Background()
  116. if err := manager.initBaremetals(ctx, files); err != nil {
  117. log.Warningf("init baremetals by files err: %v", err)
  118. }
  119. agent.Manager = manager
  120. agent.startPXEServices(manager)
  121. agent.startFileServer()
  122. agent.DoOnline(agent.GetAdminSession())
  123. return nil
  124. }
  125. func (agent *SBaremetalAgent) StopService() error {
  126. if agent.Manager != nil {
  127. agent.Manager.Stop()
  128. }
  129. return nil
  130. }
  131. func (agent *SBaremetalAgent) GetManager() *SBaremetalManager {
  132. return agent.Manager
  133. }
  134. func (agent *SBaremetalAgent) TuneSystem() error {
  135. agent.disableUDPOffloading()
  136. return nil
  137. }
  138. func (agent *SBaremetalAgent) disableUDPOffloading() {
  139. log.Infof("Disable UDP offloading")
  140. offTx := procutils.NewCommand("ethtool", "--offload", o.Options.ListenInterface, "tx", "off")
  141. offTx.Run()
  142. offGso := procutils.NewCommand("ethtool", "-K", o.Options.ListenInterface, "gso", "off")
  143. offGso.Run()
  144. }
  145. func (agent *SBaremetalAgent) startPXEServices(manager *SBaremetalManager) {
  146. dhcpListenIp, err := agent.GetDHCPServerListenIP()
  147. if err != nil {
  148. log.Fatalf("Get dhcp listen ip address error: %v", err)
  149. }
  150. agent.PXEServer = &pxe.Server{
  151. TFTPRootDir: o.Options.TftpRoot,
  152. Address: dhcpListenIp.String(),
  153. BaremetalManager: manager,
  154. ListenIface: agent.ListenInterface.Name,
  155. }
  156. go func() {
  157. err := agent.PXEServer.Serve()
  158. if err != nil {
  159. log.Fatalf("Start PXE server error: %v", err)
  160. }
  161. }()
  162. }
  163. func (agent *SBaremetalAgent) startFileServer() {
  164. dhcpListenIp, err := agent.GetDHCPServerListenIP()
  165. if err != nil {
  166. log.Fatalf("Get dhcp listen ip address error: %v", err)
  167. }
  168. fs := http.FileServer(httputils.Dir(o.Options.TftpRoot))
  169. http.Handle("/tftp/", http.StripPrefix("/tftp/", fs))
  170. cacheFs := http.FileServer(httputils.Dir(o.Options.CachePath))
  171. http.Handle("/images/", http.StripPrefix("/images/", cacheFs))
  172. isoFs := http.FileServer(httputils.Dir(o.Options.BootIsoPath))
  173. http.Handle("/bootiso/", http.StripPrefix("/bootiso/", isoFs))
  174. go func() {
  175. if err := http.ListenAndServe(fmt.Sprintf("%s:%d", dhcpListenIp, o.Options.Port+1000), nil); err != nil {
  176. panic(fmt.Sprintf("start http file server: %v", err))
  177. }
  178. }()
  179. }
  180. func Start(app *appsrv.Application) error {
  181. var err error
  182. if baremetalAgent != nil {
  183. log.Warningf("Global baremetalAgent already start")
  184. return nil
  185. }
  186. baremetalAgent, err = newBaremetalAgent()
  187. if err != nil {
  188. return err
  189. }
  190. err = baremetalAgent.Start()
  191. if err != nil {
  192. return err
  193. }
  194. baremetalAgent.AddImageCacheHandler("", app)
  195. return nil
  196. }
  197. func Stop() error {
  198. if baremetalAgent != nil {
  199. log.Infof("baremetalAgent stop ...")
  200. tmpAgent := baremetalAgent
  201. baremetalAgent = nil
  202. tmpAgent.Stop()
  203. }
  204. return nil
  205. }
  206. func GetBaremetalAgent() *SBaremetalAgent {
  207. return baremetalAgent
  208. }
  209. func GetBaremetalManager() *SBaremetalManager {
  210. return GetBaremetalAgent().GetManager()
  211. }