11package hosts
22
33import (
4- "context"
54 "fmt"
65 "log"
6+ "os"
7+
8+ "maps"
79
810 serverscom "github.com/serverscom/serverscom-go-client/pkg"
911 "github.com/serverscom/srvctl/cmd/base"
1012 "github.com/spf13/cobra"
13+ "github.com/spf13/pflag"
1114)
1215
13- type HostCreator interface {
14- Create (ctx context.Context , client * serverscom.Client , input any ) (any , error )
15- NewCreateInput () any
16+ type AddDSFlags struct {
17+ InputPath string
18+ LocationID int
19+ ServerModelID int
20+ OperatingSystemID int
21+ Features []string
22+ RAMSize int
23+ PublicUplinkID int
24+ PublicBandwidthID int
25+ PrivateUplinkID int
26+ DriveSlots map [string ]int
27+ Layout []string
28+ Partitions []string
29+ IPv6 bool
30+ UserDataFile string
31+ UserData string
32+ Labels map [string ]string
1633}
1734
18- type DSCreateMgr struct {}
35+ func applyFlagsToInput (
36+ input * serverscom.DedicatedServerCreateInput ,
37+ flags * AddDSFlags ,
38+ pflags * pflag.FlagSet ,
39+ ) error {
40+ if pflags .Changed ("location-id" ) {
41+ input .LocationID = int64 (flags .LocationID )
42+ }
43+ if pflags .Changed ("server-model-id" ) {
44+ input .ServerModelID = int64 (flags .ServerModelID )
45+ }
46+ if pflags .Changed ("operating-system-id" ) {
47+ val := int64 (flags .OperatingSystemID )
48+ input .OperatingSystemID = & val
49+ }
50+ if pflags .Changed ("feature" ) {
51+ input .Features = flags .Features
52+ }
53+ if pflags .Changed ("ram-size" ) {
54+ input .RAMSize = flags .RAMSize
55+ }
56+ if pflags .Changed ("public-uplink-id" ) {
57+ if input .UplinkModels .Public == nil {
58+ input .UplinkModels .Public = & serverscom.DedicatedServerPublicUplinkInput {}
59+ }
60+ input .UplinkModels .Public .ID = int64 (flags .PublicUplinkID )
61+ }
62+ if pflags .Changed ("public-bandwidth-id" ) {
63+ if input .UplinkModels .Public == nil {
64+ input .UplinkModels .Public = & serverscom.DedicatedServerPublicUplinkInput {}
65+ }
66+ input .UplinkModels .Public .BandwidthModelID = int64 (flags .PublicBandwidthID )
67+ }
68+ if pflags .Changed ("private-uplink-id" ) {
69+ input .UplinkModels .Private .ID = int64 (flags .PrivateUplinkID )
70+ }
1971
20- func (c * DSCreateMgr ) Create (ctx context.Context , client * serverscom.Client , input any ) (any , error ) {
21- dsInput , ok := input .(* serverscom.DedicatedServerCreateInput )
22- if ! ok {
23- return nil , fmt .Errorf ("invalid input type for dedicated server" )
72+ if pflags .Changed ("drive-slots" ) {
73+ slots , err := parseDriveSlots (flags .DriveSlots )
74+ if err != nil {
75+ return err
76+ }
77+ input .Drives .Slots = slots
2478 }
25- return client .Hosts .CreateDedicatedServers (ctx , * dsInput )
26- }
2779
28- func (c * DSCreateMgr ) NewCreateInput () any {
29- return & serverscom.DedicatedServerCreateInput {}
30- }
80+ if pflags .Changed ("layout" ) {
81+ layouts , err := parseLayout (flags .Layout )
82+ if err != nil {
83+ return err
84+ }
85+ input .Drives .Layout = mergeLayouts (input .Drives .Layout , layouts )
86+ }
3187
32- type SBMCreateMgr struct {}
88+ if pflags .Changed ("partition" ) {
89+ if len (input .Drives .Layout ) == 0 {
90+ return fmt .Errorf ("partition given but layout is empty" )
91+ }
92+ partitions , err := parsePartitions (flags .Partitions )
93+ if err != nil {
94+ return err
95+ }
96+ err = applyPartitions (input .Drives .Layout , partitions )
97+ if err != nil {
98+ return err
99+ }
100+ }
101+ if pflags .Changed ("ipv6" ) {
102+ input .IPv6 = flags .IPv6
103+ }
104+ if pflags .Changed ("user-data" ) && pflags .Changed ("user-data-file" ) {
105+ return fmt .Errorf ("'user-data' and 'user-data-file' can't be used together" )
106+ }
107+ if pflags .Changed ("user-data-file" ) {
108+ data , err := os .ReadFile (flags .UserDataFile )
109+ if err != nil {
110+ return fmt .Errorf ("can't read user-data-file: %v" , err )
111+ }
112+ dataStr := string (data )
113+ input .UserData = & dataStr
114+ }
115+ if pflags .Changed ("user-data" ) {
116+ input .UserData = & flags .UserData
117+ }
33118
34- func ( c * SBMCreateMgr ) Create ( ctx context. Context , client * serverscom. Client , input any ) ( any , error ) {
35- sbmInput , ok := input .( * serverscom. SBMServerCreateInput )
36- if ! ok {
37- return nil , fmt . Errorf ( "invalid input type for SBM server" )
119+ if pflags . Changed ( "labels" ) {
120+ for i := range input .Hosts {
121+ maps . Copy ( input . Hosts [ i ]. Labels , flags . Labels )
122+ }
38123 }
39- return client . Hosts . CreateSBMServers ( ctx , * sbmInput )
124+ return nil
40125}
41126
42- func (c * SBMCreateMgr ) NewCreateInput () any {
43- return & serverscom.SBMServerCreateInput {}
127+ func newAddDSCmd (cmdContext * base.CmdContext ) * cobra.Command {
128+ flags := & AddDSFlags {}
129+
130+ cmd := & cobra.Command {
131+ Use : "add" ,
132+ Short : "Create a dedicated server" ,
133+ Args : cobra .ArbitraryArgs ,
134+ RunE : func (cmd * cobra.Command , args []string ) error {
135+
136+ manager := cmdContext .GetManager ()
137+ ctx , cancel := base .SetupContext (cmd , manager )
138+ defer cancel ()
139+
140+ base .SetupProxy (cmd , manager )
141+
142+ input := serverscom.DedicatedServerCreateInput {}
143+
144+ if flags .InputPath != "" {
145+ if err := base .ReadInputJSON (flags .InputPath , cmd .InOrStdin (), & input ); err != nil {
146+ return err
147+ }
148+ }
149+
150+ if len (input .Hosts ) == 0 && len (args ) == 0 {
151+ return fmt .Errorf ("no hosts found from positional args and no hosts found from input, can't continue" )
152+ }
153+
154+ for _ , hostname := range args {
155+ input .Hosts = append (input .Hosts , serverscom.DedicatedServerHostInput {
156+ Hostname : hostname ,
157+ Labels : make (map [string ]string ),
158+ })
159+ }
160+
161+ err := applyFlagsToInput (& input , flags , cmd .Flags ())
162+ if err != nil {
163+ return err
164+ }
165+
166+ scClient := cmdContext .GetClient ().SetVerbose (manager .GetVerbose (cmd )).GetScClient ()
167+
168+ server , err := scClient .Hosts .CreateDedicatedServers (ctx , input )
169+ if err != nil {
170+ return err
171+ }
172+
173+ if server != nil {
174+ formatter := cmdContext .GetOrCreateFormatter (cmd )
175+ return formatter .Format (server )
176+ }
177+
178+ return nil
179+ },
180+ }
181+
182+ cmd .Flags ().StringVarP (& flags .InputPath , "input" , "i" , "" , "path to input file or '-' to read from stdin" )
183+
184+ cmd .Flags ().IntVar (& flags .LocationID , "location-id" , 0 , "Create the server(s) in the specific location ID" )
185+ cmd .Flags ().IntVar (& flags .ServerModelID , "server-model-id" , 0 , "Use specific server model ID to create the server" )
186+ cmd .Flags ().IntVar (& flags .OperatingSystemID , "operating-system-id" , 0 , "Install the specific operating system" )
187+ cmd .Flags ().StringSliceVar (& flags .Features , "feature" , nil , "Set of features" )
188+ cmd .Flags ().IntVar (& flags .RAMSize , "ram-size" , 0 , "Desired amount of RAM in GB" )
189+ cmd .Flags ().IntVar (& flags .PublicUplinkID , "public-uplink-id" , 0 , "The public uplink ID, can be omitted if do not want public uplink" )
190+ cmd .Flags ().IntVar (& flags .PrivateUplinkID , "private-uplink-id" , 0 , "The private uplink ID" )
191+ cmd .Flags ().IntVar (& flags .PublicBandwidthID , "public-bandwidth-id" , 0 , "The public bandwidth ID, MUST be omitted if public uplink id is not passed" )
192+ cmd .Flags ().StringToIntVar (& flags .DriveSlots , "drive-slots" , nil , "mapping of the specific slot to the specific drive model" )
193+ cmd .Flags ().StringArrayVar (& flags .Layout , "layout" , nil , "Configuration of drives layout" )
194+ cmd .Flags ().StringArrayVar (& flags .Partitions , "partition" , nil , "Configuration of the specific partitions" )
195+ cmd .Flags ().BoolVar (& flags .IPv6 , "ipv6" , false , "Enable IPv6" )
196+ cmd .Flags ().StringVar (& flags .UserDataFile , "user-data-file" , "" , "Path to user data which should be readed" )
197+ cmd .Flags ().StringVar (& flags .UserData , "user-data" , "" , "Content of user data" )
198+ cmd .Flags ().StringToStringVar (& flags .Labels , "labels" , nil , "The set of labels which will be applied to the all hosts of this operation" )
199+
200+ return cmd
44201}
45202
46- func newAddCmd (cmdContext * base.CmdContext , hostType * HostTypeCmd ) * cobra.Command {
203+ func newAddSBMCmd (cmdContext * base.CmdContext ) * cobra.Command {
47204 var path string
48205 cmd := & cobra.Command {
49206 Use : "add --input <path>" ,
50- Short : fmt . Sprintf ( "Create a %s" , hostType . entityName ) ,
207+ Short : "Create an SBM server" ,
51208 Args : cobra .ExactArgs (0 ),
52209 RunE : func (cmd * cobra.Command , args []string ) error {
53210 manager := cmdContext .GetManager ()
@@ -56,15 +213,15 @@ func newAddCmd(cmdContext *base.CmdContext, hostType *HostTypeCmd) *cobra.Comman
56213
57214 base .SetupProxy (cmd , manager )
58215
59- input := hostType . managers . createMgr . NewCreateInput ()
216+ input := serverscom. SBMServerCreateInput {}
60217
61- if err := base .ReadInputJSON (path , cmd .InOrStdin (), input ); err != nil {
218+ if err := base .ReadInputJSON (path , cmd .InOrStdin (), & input ); err != nil {
62219 return err
63220 }
64221
65222 scClient := cmdContext .GetClient ().SetVerbose (manager .GetVerbose (cmd )).GetScClient ()
66223
67- server , err := hostType . managers . createMgr . Create (ctx , scClient , input )
224+ server , err := scClient . Hosts . CreateSBMServers (ctx , input )
68225 if err != nil {
69226 return err
70227 }
0 commit comments