11package proxmox
22
33import (
4+ "crypto/sha256"
45 "crypto/tls"
56 "errors"
7+ "fmt"
68 "net/http"
9+ "sync"
710
811 "github.com/sp-yduck/proxmox-go/rest"
912)
1013
14+ var (
15+ // global Service map against sessionKeys in map[sessionKey]Session
16+ sessionCache sync.Map
17+
18+ // mutex to control access to the GetOrCreate function to avoid duplicate
19+ // session creations on startup
20+ sessionMutex sync.Mutex
21+ )
22+
1123type Service struct {
1224 restclient * rest.RESTClient
1325}
1426
27+ type Params struct {
28+ // base endpoint of proxmox rest api
29+ endpoint string
30+
31+ // auth config
32+ authConfig AuthConfig
33+
34+ // rest client config
35+ clientConfig ClientConfig
36+ }
37+
38+ type ClientConfig struct {
39+ InsecureSkipVerify bool
40+ }
41+
1542type AuthConfig struct {
16- Username string
17- Password string
18- TokenID string
19- Secret string
43+ // user or token
44+ AuthMethod string
45+ Username string
46+ Password string
47+ TokenID string
48+ Secret string
2049}
2150
22- func NewService (url string , authConfig AuthConfig , insecure bool ) (* Service , error ) {
23- var loginOption rest.ClientOption
24- if authConfig .Username != "" && authConfig .Password != "" {
25- loginOption = rest .WithUserPassword (authConfig .Username , authConfig .Password )
26- } else if authConfig .TokenID != "" && authConfig .Secret != "" {
27- loginOption = rest .WithAPIToken (authConfig .TokenID , authConfig .Secret )
28- } else {
29- return nil , errors .New ("invalid authentication config" )
51+ func GetOrCreateService (params Params ) (* Service , error ) {
52+ sessionMutex .Lock ()
53+ defer sessionMutex .Unlock ()
54+
55+ key := retrieveSessionKey (params )
56+ if cachedSession , ok := sessionCache .Load (key ); ok {
57+ return cachedSession .(* Service ), nil
58+ }
59+
60+ s , err := NewService (params )
61+ if err != nil {
62+ return nil , err
63+ }
64+ sessionCache .Store (key , s )
65+ return s , nil
66+ }
67+
68+ func NewService (params Params ) (* Service , error ) {
69+ loginOption , err := makeLoginOpts (params .authConfig )
70+ if err != nil {
71+ return nil , err
3072 }
3173 clientOptions := []rest.ClientOption {loginOption }
3274
33- if insecure {
75+ if params . clientConfig . InsecureSkipVerify {
3476 baseClient := & http.Client {
3577 Transport : & http.Transport {
3678 TLSClientConfig : & tls.Config {
@@ -41,7 +83,7 @@ func NewService(url string, authConfig AuthConfig, insecure bool) (*Service, err
4183 clientOptions = append (clientOptions , rest .WithClient (baseClient ))
4284 }
4385
44- restclient , err := rest .NewRESTClient (url , clientOptions ... )
86+ restclient , err := rest .NewRESTClient (params . endpoint , clientOptions ... )
4587 if err != nil {
4688 return nil , err
4789 }
@@ -96,3 +138,33 @@ func NewServiceWithAPIToken(url, tokenid, secret string, insecure bool) (*Servic
96138func (s * Service ) RESTClient () * rest.RESTClient {
97139 return s .restclient
98140}
141+
142+ func makeLoginOpts (authConfig AuthConfig ) (rest.ClientOption , error ) {
143+ if authConfig .AuthMethod == "token" && authConfig .TokenID != "" && authConfig .Secret != "" {
144+ return rest .WithAPIToken (authConfig .TokenID , authConfig .Secret ), nil
145+ } else if authConfig .AuthMethod == "user" && authConfig .Username != "" && authConfig .Password != "" {
146+ return rest .WithUserPassword (authConfig .Username , authConfig .Password ), nil
147+ }
148+ return nil , errors .New ("invalid authentication config" )
149+ }
150+
151+ func retrieveSessionKey (params Params ) string {
152+ var id string
153+ var secret []byte
154+ h := sha256 .New ()
155+ switch params .authConfig .AuthMethod {
156+ case "token" :
157+ id = params .authConfig .TokenID
158+ h .Write ([]byte (params .authConfig .Secret ))
159+ secret = h .Sum (nil )
160+ case "user" :
161+ id = params .authConfig .Username
162+ h .Write ([]byte (params .authConfig .Password ))
163+ secret = h .Sum (nil )
164+ default :
165+ id = params .authConfig .Username
166+ h .Write ([]byte (params .authConfig .Password ))
167+ secret = h .Sum (nil )
168+ }
169+ return fmt .Sprintf ("%s#%s#%x" , params .endpoint , id , secret )
170+ }
0 commit comments