From 3b6ed8a8392048f83cdc91035cc0dcd482776b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= <hugo@lysator.liu.se> Date: Mon, 2 Nov 2020 20:07:51 +0100 Subject: [PATCH] Restructure into modules. --- dir/dir.go | 107 ++++++++++++++ fetch/fetch.go | 256 +++++++++++++++++++++++++++++++++ file/file.go | 27 ++++ go.mod | 7 +- link/link.go | 20 +++ main.go | 379 +------------------------------------------------ 6 files changed, 422 insertions(+), 374 deletions(-) create mode 100644 dir/dir.go create mode 100644 fetch/fetch.go create mode 100644 file/file.go create mode 100644 link/link.go diff --git a/dir/dir.go b/dir/dir.go new file mode 100644 index 0000000..8cbca4a --- /dev/null +++ b/dir/dir.go @@ -0,0 +1,107 @@ +package dir + +import ( + "context" + "os" + "syscall" + "bazil.org/fuse" + "bazil.org/fuse/fs" + "git.lysator.liu.se/hugo/foremanFS/fetch" + "git.lysator.liu.se/hugo/foremanFS/link" + "git.lysator.liu.se/hugo/foremanFS/file" +) + +type DirRoot struct { } +type DirHostList struct { } +type DirHost struct { hostname string } +type DirHostClasses struct { hostname string } + +func (DirRoot) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 0 + a.Mode = os.ModeDir | 0o555 + return nil +} + +func (DirHostList) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 0 + a.Mode = os.ModeDir | 0o555 + return nil +} + +func (DirHost) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 0 + a.Mode = os.ModeDir | 0o555 + return nil +} + +func (DirHostClasses) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 0 + a.Mode = os.ModeDir | 0o555 + return nil +} + +func (DirRoot) Lookup(ctx context.Context, name string) (fs.Node, error) { + if name == "hosts" { + return DirHostList{}, nil + } else { + return nil, syscall.ENOENT + } +} + + +func (DirHostList) Lookup(ctx context.Context, name string) (fs.Node, error) { + _, ok := fetch.Hosts[name] + if ! ok { + return nil, syscall.ENOENT + } + return DirHost{ name }, nil +} + +func (d DirHostClasses) Lookup(ctx context.Context, name string) (fs.Node, error) { + classes := fetch.GetClassList(fetch.Hosts[d.hostname].Data) + + for _, class := range classes { + if name == class { + return link.LinkPuppetClass{ class }, nil + } + } + + return nil, syscall.ENOENT +} + +func (d DirHost) Lookup(ctx context.Context, name string) (fs.Node, error) { + switch name { + case "data": return file.DataFile{ d.hostname }, nil + case "classes": return DirHostClasses{ d.hostname }, nil + } + return nil, syscall.ENOENT +} + +func (DirRoot)ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + return []fuse.Dirent{ {Inode: 0, Name: "hosts", Type: fuse.DT_Dir}, }, nil +} + +func (DirHostList)ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + var dirents []fuse.Dirent + for _, item := range fetch.Hosts { + dirents = append(dirents, fuse.Dirent{Inode: 0, Name: item.Data.Name, Type: fuse.DT_Dir}) + } + return dirents, nil +} + +func (DirHost)ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + return []fuse.Dirent{ + {Inode: 0, Name: "data", Type: fuse.DT_File}, + {Inode: 0, Name: "classes", Type: fuse.DT_Dir}, + }, nil +} + +func (d DirHostClasses)ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + classes := fetch.GetClassList(fetch.Hosts[d.hostname].Data) + + var out []fuse.Dirent + for _, class := range classes { + out = append(out, fuse.Dirent{ Inode: 0, Name: class, Type: fuse.DT_Link }) + } + return out, nil +} diff --git a/fetch/fetch.go b/fetch/fetch.go new file mode 100644 index 0000000..c3d54ee --- /dev/null +++ b/fetch/fetch.go @@ -0,0 +1,256 @@ +package fetch + +import ( + "fmt" + "log" + + "crypto/tls" + "encoding/json" + "net/http" +) + +var Hosts = map[string]Host{} +const apiurl = "https://chapman.lysator.liu.se/api/" +var classes map[float64]Puppetclass +var password string +var client *http.Client + +type Host struct { + Data ResultRecord +} + +func Init (pw string) { + + password = pw + + classes = map[float64]Puppetclass{} + + tr := &http.Transport { + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + + client = &http.Client { Transport: tr } + + + request, err := http.NewRequest("GET", apiurl + "hosts", nil) + if err != nil { + log.Fatal(err); + } + request.SetBasicAuth("hugo", password); + + log.Print("Getting host list") + resp, err := client.Do(request) + if err != nil { + log.Fatal(err); + } + defer resp.Body.Close() + + + + // echo curl --user "hugo:$(pass lysator/hugo)" -k https://chapman.lysator.liu.se/api/hosts + + + log.Print("Parsing host list"); + decoder := json.NewDecoder(resp.Body); + var m Message + err = decoder.Decode(&m) + if err != nil { + log.Fatal(err); + } + // var data []ResultRecord + // data := m.Results + + for _, record := range m.Results { + /* + if record.Owner_name == "Hugo Hörnquist" { + fmt.Printf("%v\n", record.Name) + } + */ + Hosts[record.Name] = Host{ record } + } +} + +func GetClassList (host ResultRecord) ([]string) { + var record Puppetclass + + if val, ok := classes[host.Id]; ok { + record = val + } else { + url := fmt.Sprintf(apiurl + "hosts/%d/puppetclasses", int(host.Id)); + request, err := http.NewRequest("GET",url, nil) + if err != nil { + log.Fatal(err); + } + request.SetBasicAuth("hugo", password); + + resp, err := client.Do(request) + if err != nil { + log.Fatal(err); + } + defer resp.Body.Close() + + decoder := json.NewDecoder(resp.Body); + var m PuppetclassMessage + err = decoder.Decode(&m) + if err != nil { + log.Fatal(err); + } + + classes[host.Id] = m.Results + record = m.Results + } + + str := []string{} + for _, r := range record.Profiles { + str = append(str, r.Name) + } + return str +} + + +type ResultRecord struct { + Ip string // "130.236.254.139", + Ip6 string // "2001:6b0:17:f0a0::8b", + Environment_id float64 // 1, + Environment_name string // "production", + Last_report string // "2020-10-28 19:10:57 UTC", + Mac string // "1c:c1:de:03:e7:b6", + /* + "realm_id": null, + "realm_name": null, + "sp_mac": null, + "sp_ip": null, + "sp_name": null, + */ + Domain_id float64 // 1, + Domain_name string // "lysator.liu.se", + Architecture_id float64 // 1, + Architecture_name string // "x86_64", + Operatingsystem_id float64 // 6, + Operatingsystem_name string // "CentOS Linux 7.8.2003", + /* + "subnet_id": null, + "subnet_name": null, + "subnet6_id": null, + "subnet6_name": null, + "sp_subnet_id": null, + "ptable_id": null, + "ptable_name": null, + "medium_id": null, + "medium_name": null, + "pxe_loader": null, + "build": false, + */ + Comment string // "", + /* + "disk": null, + "installed_at": null, + */ + Model_id float64 // 3, + Hostgroup_id float64 // 6, + Owner_id float64 // 5, + Owner_name string // "Henrik Henriksson", + Owner_type string // "User", + Enabled bool // true, + Managed bool // false, + /* + "use_image": null, + */ + Image_file string // "", + /* + "uuid": null, + "compute_resource_id": null, + "compute_resource_name": null, + "compute_profile_id": null, + "compute_profile_name": null, + */ + // capabilities []interface{} // [ "build" ], + Provision_method string // "build", + Certname string // "analysator-system.lysator.liu.se", + /* + "image_id": null, + "image_name": null, + */ + Created_at string // "2020-08-16 19:51:59 UTC", + Updated_at string // "2020-10-28 19:11:26 UTC", + /* + "last_compile": null, + */ + Global_status float64 // 0, + Global_status_label string // "OK", + Uptime_seconds float64 // 20857465, + Organization_id float64 // 1, + Organization_name string // "Lysator", + Location_id float64 // 2, + Location_name string // "Foo", + Puppet_status float64 // 0, + Model_name string // "ProLiant DL180 G6", + Configuration_status float64 // 0, + Configuration_status_label string // "No changes", + Name string // "analysator-system.lysator.liu.se", + Id float64 // 13, + Puppet_proxy_id float64 // 1, + Puppet_proxy_name string // "chapman.lysator.liu.se", + Puppet_ca_proxy_id float64 // 1, + Puppet_ca_proxy_name string // "chapman.lysator.liu.se", + /* + "puppet_proxy": { + "name": "chapman.lysator.liu.se", + "id": 1, + "url": "https://chapman.lysator.liu.se:8443" + }, + "puppet_ca_proxy": { + "name": "chapman.lysator.liu.se", + "id": 1, + "url": "https://chapman.lysator.liu.se:8443" + }, + */ + Hostgroup_name string // "System", + Hostgroup_title string // "Analysator/System" +} + +type Message struct { + Total, Subtotal, Page/*, Per_page*/ float64 + Results []ResultRecord + // search + // sort { by, order null } +} + +type Puppetclass struct { + + Profiles []struct { + Id float64 + Name string + Created_at string + Updated_at string + } + + /* + [{"id":433,"name":"profiles::elvisp","created_at":"2020-10-27T07:57:47.102Z","updated_at":"2020-10-27T07:57:47.102Z"}, + {"id":243,"name":"profiles::service","created_at":"2020-08-16T15:07:23.431Z","updated_at":"2020-08-16T15:07:23.431Z"}, + {"id":434,"name":"profiles::vitellary","created_at":"2020 -10-27T07:57:47.130Z","updated_at":"2020-10-27T07:57:47.130Z"}]} + */ + + /* + { + "total": 3, + "subtotal": 3, + "page": 1, + "per_page": 50, + "search": null, + "sort": { + "by": null, + "order": null + }, + "results": {"profiles":[{"id":433,"name":"profiles::elvisp","created_at":"2020-10-27T07:57:47.102Z","updated_at":"2020-10-27T07:57:47.102Z"},{"id":243,"name" + :"profiles::service","created_at":"2020-08-16T15:07:23.431Z","updated_at":"2020-08-16T15:07:23.431Z"},{"id":434,"name":"profiles::vitellary","created_at":"2020 + -10-27T07:57:47.130Z","updated_at":"2020-10-27T07:57:47.130Z"}]} + } + */ +} + +type PuppetclassMessage struct { + Total, Subtotal, Page/*, Per_page*/ float64 + Results Puppetclass +} + diff --git a/file/file.go b/file/file.go new file mode 100644 index 0000000..6f767b1 --- /dev/null +++ b/file/file.go @@ -0,0 +1,27 @@ +package file + +import ( + "context" + "bazil.org/fuse" + "fmt" + "git.lysator.liu.se/hugo/foremanFS/fetch" +) + +type DataFile struct { + // record ResultRecord + Hostname string +} + + +func (f DataFile) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 0 + a.Mode = 0o444 + // a.Size = uint64(len(fmt.Sprintf("%+v\n", f.record))) + // a.Size = uint64(len(greeting)) + a.Size = uint64(len(fmt.Sprintf("%+v\n", fetch.Hosts[f.Hostname]))) + return nil +} + +func (f DataFile) ReadAll(ctx context.Context) ([]byte, error) { + return []byte(fmt.Sprintf("%+v\n", fetch.Hosts[f.Hostname])), nil +} diff --git a/go.mod b/go.mod index 8fb12ea..ba9ae91 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,8 @@ -module lysator.liu.se/foreman-fuse +module git.lysator.liu.se/hugo/foremanFS go 1.15 -require bazil.org/fuse v0.0.0-20200524192727-fb710f7dfd05 // indirect +require ( + bazil.org/fuse v0.0.0-20200524192727-fb710f7dfd05 +) + diff --git a/link/link.go b/link/link.go new file mode 100644 index 0000000..1f3670f --- /dev/null +++ b/link/link.go @@ -0,0 +1,20 @@ +package link + +import ( + "context" + "os" + "bazil.org/fuse" +) + +type LinkPuppetClass struct { Classname string } + +func (LinkPuppetClass) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 0 + a.Mode = os.ModeSymlink | 0o444 + return nil +} + + + + + diff --git a/main.go b/main.go index 5301e75..4ae44d8 100644 --- a/main.go +++ b/main.go @@ -1,80 +1,29 @@ package main import ( - "fmt" + "log" "os" - "context" - "syscall" _ "strings" - "crypto/tls" - "encoding/json" - "net/http" + "git.lysator.liu.se/hugo/foremanFS/dir" + "git.lysator.liu.se/hugo/foremanFS/fetch" + "bazil.org/fuse" "bazil.org/fuse/fs" _ "bazil.org/fuse/fs/fstestutil" ) -var client *http.Client -var password string -var classes map[float64]Puppetclass -var hosts = map[string]Host{} var classesForHost = map[string][]string{} // const apiurl := "http://localhost:8000/hosts.json" -const apiurl = "https://chapman.lysator.liu.se/api/" func main() { - password = os.Args[1:][0] - - classes = map[float64]Puppetclass{} - - tr := &http.Transport { - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - - client = &http.Client { Transport: tr } - - - request, err := http.NewRequest("GET", apiurl + "hosts", nil) - if err != nil { - log.Fatal(err); - } - request.SetBasicAuth("hugo", password); - - log.Print("Getting host list") - resp, err := client.Do(request) - if err != nil { - log.Fatal(err); - } - defer resp.Body.Close() - - - - // echo curl --user "hugo:$(pass lysator/hugo)" -k https://chapman.lysator.liu.se/api/hosts - - - log.Print("Parsing host list"); - decoder := json.NewDecoder(resp.Body); - var m Message - err = decoder.Decode(&m) - if err != nil { - log.Fatal(err); - } - // var data []ResultRecord - // data := m.Results + password := os.Args[1:][0] - for _, record := range m.Results { - /* - if record.Owner_name == "Hugo Hörnquist" { - fmt.Printf("%v\n", record.Name) - } - */ - hosts[record.Name] = Host{ record } - } + fetch.Init(password) c, err := fuse.Mount( "mnt", @@ -96,151 +45,6 @@ func main() { } -func getClassList (host ResultRecord) ([]string) { - var record Puppetclass - - if val, ok := classes[host.Id]; ok { - record = val - } else { - url := fmt.Sprintf(apiurl + "hosts/%d/puppetclasses", int(host.Id)); - request, err := http.NewRequest("GET",url, nil) - if err != nil { - log.Fatal(err); - } - request.SetBasicAuth("hugo", password); - - resp, err := client.Do(request) - if err != nil { - log.Fatal(err); - } - defer resp.Body.Close() - - decoder := json.NewDecoder(resp.Body); - var m PuppetclassMessage - err = decoder.Decode(&m) - if err != nil { - log.Fatal(err); - } - - classes[host.Id] = m.Results - record = m.Results - } - - str := []string{} - for _, r := range record.Profiles { - str = append(str, r.Name) - } - return str -} - - -type ResultRecord struct { - Ip string // "130.236.254.139", - Ip6 string // "2001:6b0:17:f0a0::8b", - Environment_id float64 // 1, - Environment_name string // "production", - Last_report string // "2020-10-28 19:10:57 UTC", - Mac string // "1c:c1:de:03:e7:b6", - /* - "realm_id": null, - "realm_name": null, - "sp_mac": null, - "sp_ip": null, - "sp_name": null, - */ - Domain_id float64 // 1, - Domain_name string // "lysator.liu.se", - Architecture_id float64 // 1, - Architecture_name string // "x86_64", - Operatingsystem_id float64 // 6, - Operatingsystem_name string // "CentOS Linux 7.8.2003", - /* - "subnet_id": null, - "subnet_name": null, - "subnet6_id": null, - "subnet6_name": null, - "sp_subnet_id": null, - "ptable_id": null, - "ptable_name": null, - "medium_id": null, - "medium_name": null, - "pxe_loader": null, - "build": false, - */ - Comment string // "", - /* - "disk": null, - "installed_at": null, - */ - Model_id float64 // 3, - Hostgroup_id float64 // 6, - Owner_id float64 // 5, - Owner_name string // "Henrik Henriksson", - Owner_type string // "User", - Enabled bool // true, - Managed bool // false, - /* - "use_image": null, - */ - Image_file string // "", - /* - "uuid": null, - "compute_resource_id": null, - "compute_resource_name": null, - "compute_profile_id": null, - "compute_profile_name": null, - */ - // capabilities []interface{} // [ "build" ], - Provision_method string // "build", - Certname string // "analysator-system.lysator.liu.se", - /* - "image_id": null, - "image_name": null, - */ - Created_at string // "2020-08-16 19:51:59 UTC", - Updated_at string // "2020-10-28 19:11:26 UTC", - /* - "last_compile": null, - */ - Global_status float64 // 0, - Global_status_label string // "OK", - Uptime_seconds float64 // 20857465, - Organization_id float64 // 1, - Organization_name string // "Lysator", - Location_id float64 // 2, - Location_name string // "Foo", - Puppet_status float64 // 0, - Model_name string // "ProLiant DL180 G6", - Configuration_status float64 // 0, - Configuration_status_label string // "No changes", - Name string // "analysator-system.lysator.liu.se", - Id float64 // 13, - Puppet_proxy_id float64 // 1, - Puppet_proxy_name string // "chapman.lysator.liu.se", - Puppet_ca_proxy_id float64 // 1, - Puppet_ca_proxy_name string // "chapman.lysator.liu.se", - /* - "puppet_proxy": { - "name": "chapman.lysator.liu.se", - "id": 1, - "url": "https://chapman.lysator.liu.se:8443" - }, - "puppet_ca_proxy": { - "name": "chapman.lysator.liu.se", - "id": 1, - "url": "https://chapman.lysator.liu.se:8443" - }, - */ - Hostgroup_name string // "System", - Hostgroup_title string // "Analysator/System" -} - -type Message struct { - Total, Subtotal, Page/*, Per_page*/ float64 - Results []ResultRecord - // search - // sort { by, order null } -} type FS struct{ // data []ResultRecord @@ -248,7 +52,7 @@ type FS struct{ func (fs FS) Root() (fs.Node, error) { // return Dir{ /*fs.data*/ }, nil - return DirHostList{ /*fs.data*/ }, nil + return dir.DirHostList{ /*fs.data*/ }, nil } /* @@ -274,172 +78,3 @@ type Dir struct{ name string } */ - -type DirRoot struct { } -type DirHostList struct { } -type DirHost struct { hostname string } -type DirHostClasses struct { hostname string } - -type LinkPuppetClass struct { classname string } - - -func (LinkPuppetClass) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 0 - a.Mode = os.ModeSymlink | 0o444 - return nil -} - -func (DirRoot) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 0 - a.Mode = os.ModeDir | 0o555 - return nil -} - -func (DirHostList) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 0 - a.Mode = os.ModeDir | 0o555 - return nil -} - -func (DirHost) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 0 - a.Mode = os.ModeDir | 0o555 - return nil -} - -func (DirHostClasses) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 0 - a.Mode = os.ModeDir | 0o555 - return nil -} - -type Host struct { - Data ResultRecord -} - - -func (DirRoot) Lookup(ctx context.Context, name string) (fs.Node, error) { - if name == "hosts" { - return DirHostList{}, nil - } else { - return nil, syscall.ENOENT - } -} - - -func (DirHostList) Lookup(ctx context.Context, name string) (fs.Node, error) { - _, ok := hosts[name] - if ! ok { - return nil, syscall.ENOENT - } - return DirHost{ name }, nil -} - -func (d DirHostClasses) Lookup(ctx context.Context, name string) (fs.Node, error) { - classes := getClassList(hosts[d.hostname].Data) - - for _, class := range classes { - if name == class { - return LinkPuppetClass{ class }, nil - } - } - - return nil, syscall.ENOENT -} - -func (d DirHost) Lookup(ctx context.Context, name string) (fs.Node, error) { - switch name { - case "data": return DataFile{ d.hostname }, nil - case "classes": return DirHostClasses{ d.hostname }, nil - } - return nil, syscall.ENOENT -} - - -type DataFile struct { - // record ResultRecord - hostname string -} - -func (DirRoot)ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - return []fuse.Dirent{ {Inode: 0, Name: "hosts", Type: fuse.DT_Dir}, }, nil -} - -func (DirHostList)ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - var dirents []fuse.Dirent - for _, item := range hosts { - dirents = append(dirents, fuse.Dirent{Inode: 0, Name: item.Data.Name, Type: fuse.DT_Dir}) - } - return dirents, nil -} - -func (DirHost)ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - return []fuse.Dirent{ - {Inode: 0, Name: "data", Type: fuse.DT_File}, - {Inode: 0, Name: "classes", Type: fuse.DT_Dir}, - }, nil -} - -func (d DirHostClasses)ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - classes := getClassList(hosts[d.hostname].Data) - - var out []fuse.Dirent - for _, class := range classes { - out = append(out, fuse.Dirent{ Inode: 0, Name: class, Type: fuse.DT_Link }) - } - return out, nil -} - - -func (f DataFile) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 0 - a.Mode = 0o444 - // a.Size = uint64(len(fmt.Sprintf("%+v\n", f.record))) - // a.Size = uint64(len(greeting)) - a.Size = uint64(len(fmt.Sprintf("%+v\n", hosts[f.hostname]))) - return nil -} - -type Puppetclass struct { - - Profiles []struct { - Id float64 - Name string - Created_at string - Updated_at string - } - - /* - [{"id":433,"name":"profiles::elvisp","created_at":"2020-10-27T07:57:47.102Z","updated_at":"2020-10-27T07:57:47.102Z"}, - {"id":243,"name":"profiles::service","created_at":"2020-08-16T15:07:23.431Z","updated_at":"2020-08-16T15:07:23.431Z"}, - {"id":434,"name":"profiles::vitellary","created_at":"2020 -10-27T07:57:47.130Z","updated_at":"2020-10-27T07:57:47.130Z"}]} - */ - - /* - { - "total": 3, - "subtotal": 3, - "page": 1, - "per_page": 50, - "search": null, - "sort": { - "by": null, - "order": null - }, - "results": {"profiles":[{"id":433,"name":"profiles::elvisp","created_at":"2020-10-27T07:57:47.102Z","updated_at":"2020-10-27T07:57:47.102Z"},{"id":243,"name" - :"profiles::service","created_at":"2020-08-16T15:07:23.431Z","updated_at":"2020-08-16T15:07:23.431Z"},{"id":434,"name":"profiles::vitellary","created_at":"2020 - -10-27T07:57:47.130Z","updated_at":"2020-10-27T07:57:47.130Z"}]} - } - */ -} - -type PuppetclassMessage struct { - Total, Subtotal, Page/*, Per_page*/ float64 - Results Puppetclass -} - - - -func (f DataFile) ReadAll(ctx context.Context) ([]byte, error) { - return []byte(fmt.Sprintf("%+v\n", hosts[f.hostname])), nil -} -- GitLab