diff --git a/cmd/device-monitor/main.go b/cmd/device-monitor/main.go index 3beaa3c2..93bc6503 100755 --- a/cmd/device-monitor/main.go +++ b/cmd/device-monitor/main.go @@ -39,13 +39,9 @@ func main() { } log.Info("Clientset initialised") ctx := ctrl.SetupSignalHandler() - log.Info("Starting update loop") - go monitor.RunUpdateLoop( - ctx, - clientset, - os.Getenv("OPERATOR_NAMESPACE"), - clientsetKubeserial, - ) + deviceMonitor := monitor.NewMonitor(clientset, clientsetKubeserial, os.Getenv("OPERATOR_NAMESPACE"), os.Stat) + log.Info("Starting monitor update loop") + go deviceMonitor.RunUpdateLoop(ctx) <-ctx.Done() log.Info("Exiting") } diff --git a/go.mod b/go.mod index 4b98e5f1..15c90089 100644 --- a/go.mod +++ b/go.mod @@ -60,13 +60,14 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.28.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect + github.com/spf13/afero v1.8.2 github.com/spf13/cobra v1.2.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.7.1 go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect + golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect golang.org/x/mod v0.4.2 // indirect golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect diff --git a/go.sum b/go.sum index 48d9d232..48909f47 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -15,6 +16,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= @@ -37,6 +39,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= @@ -248,6 +251,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -258,6 +262,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -388,6 +393,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -437,6 +443,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= @@ -521,8 +529,10 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -598,6 +608,7 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= @@ -684,12 +695,14 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -772,6 +785,7 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -852,7 +866,9 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= diff --git a/pkg/apis/kubeserial/v1alpha1/device.go b/pkg/apis/kubeserial/v1alpha1/device.go index bb68b133..db369ec1 100644 --- a/pkg/apis/kubeserial/v1alpha1/device.go +++ b/pkg/apis/kubeserial/v1alpha1/device.go @@ -75,6 +75,7 @@ type DeviceCondition struct { // DeviceStatus defines the observed state of Device type DeviceStatus struct { Conditions []DeviceCondition `json:"conditions"` + NodeName string `json:"nodenamd,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/monitor/monitor.go b/pkg/monitor/monitor.go index 2b6d1a1b..f5b414de 100644 --- a/pkg/monitor/monitor.go +++ b/pkg/monitor/monitor.go @@ -8,6 +8,7 @@ import ( "github.com/janekbaraniewski/kubeserial/pkg/apis/kubeserial/v1alpha1" "github.com/janekbaraniewski/kubeserial/pkg/generated/clientset/versioned" + v1alpha1client "github.com/janekbaraniewski/kubeserial/pkg/generated/clientset/versioned/typed/kubeserial/v1alpha1" "github.com/janekbaraniewski/kubeserial/pkg/utils" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -20,35 +21,51 @@ import ( var log = logf.Log.WithName("ApiClient") -func RunUpdateLoop(ctx context.Context, clientset client.Interface, namespace string, clientsetKubeserial versioned.Interface) { +type Monitor struct { + cmClient v1.ConfigMapInterface + devicesClient v1alpha1client.DeviceInterface + namespace string + statFile func(filename string) (os.FileInfo, error) +} + +func NewMonitor(clientSet client.Interface, clientsetKubeserial versioned.Interface, namespace string, statFunc func(filename string) (os.FileInfo, error)) *Monitor { + return &Monitor{ + cmClient: clientSet.CoreV1().ConfigMaps(namespace), + devicesClient: clientsetKubeserial.AppV1alpha1().Devices(namespace), + namespace: namespace, + statFile: statFunc, + } +} + +func (m *Monitor) RunUpdateLoop(ctx context.Context) { for { select { case <-time.After(1 * time.Second): - UpdateDeviceState(ctx, clientset, clientsetKubeserial, namespace) + m.UpdateDeviceState(ctx) case <-ctx.Done(): return } } } -func UpdateDeviceState(ctx context.Context, clientset client.Interface, clientsetKubeserial versioned.Interface, namespace string) { +func (m *Monitor) UpdateDeviceState(ctx context.Context) { var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() - updateCMBasedDevice(ctx, clientset.CoreV1().ConfigMaps(namespace)) + m.updateCMBasedDevice(ctx) }() wg.Add(1) go func() { defer wg.Done() - UpdateCRDBasedDevice(ctx, clientsetKubeserial, namespace) + m.updateCRDBasedDevice(ctx) }() wg.Wait() } -func updateCMBasedDevice(ctx context.Context, client v1.ConfigMapInterface) { - confs, err := client.List(ctx, metav1.ListOptions{ +func (m *Monitor) updateCMBasedDevice(ctx context.Context) { + confs, err := m.cmClient.List(ctx, metav1.ListOptions{ LabelSelector: "type=DeviceState", // TODO: make configurable }) if err != nil { @@ -57,16 +74,16 @@ func updateCMBasedDevice(ctx context.Context, client v1.ConfigMapInterface) { for _, conf := range confs.Items { if conf.Data["node"] == os.Getenv("NODE_NAME") { - if !isDeviceAvailable(conf.Labels["device"]) { + if !m.isDeviceAvailable(conf.Labels["device"]) { log.Info("Device unavailable, cleaning state.") - if err := clearState(ctx, &conf, client); err != nil { + if err := m.clearState(ctx, &conf); err != nil { log.Error(err, "Update failed to clear state!") } } } else if conf.Data["available"] == "false" { - if isDeviceAvailable(conf.Labels["device"]) { + if m.isDeviceAvailable(conf.Labels["device"]) { log.Info("Device available, updating state.") - if err := setActiveState(ctx, &conf, client); err != nil { + if err := m.setActiveState(ctx, &conf); err != nil { log.Error(err, "Update failed to make device available!") } } @@ -75,10 +92,8 @@ func updateCMBasedDevice(ctx context.Context, client v1.ConfigMapInterface) { } -func UpdateCRDBasedDevice(ctx context.Context, clientset versioned.Interface, namespace string) { - client := clientset.AppV1alpha1().Devices(namespace) - - devices, err := client.List(ctx, metav1.ListOptions{ +func (m *Monitor) updateCRDBasedDevice(ctx context.Context) { + devices, err := m.devicesClient.List(ctx, metav1.ListOptions{ FieldSelector: fields.SelectorFromSet(fields.Set{ "status.conditions[].type": string(v1alpha1.DeviceReady), "status.conditions[].status": string(corev1.ConditionTrue), @@ -95,35 +110,55 @@ func UpdateCRDBasedDevice(ctx context.Context, clientset versioned.Interface, na continue } if deviceCondition.Status == metav1.ConditionFalse { - if isDeviceAvailable(device.Name) { + if m.isDeviceAvailable(device.Name) { log.Info("Device available, updating state.") - //TODO: update condition + utils.SetDeviceCondition(&device.Status.Conditions, v1alpha1.DeviceCondition{ + Type: v1alpha1.DeviceAvailable, + Status: metav1.ConditionTrue, + Reason: "DeviceAvailable", + }) + _, err := m.devicesClient.UpdateStatus(ctx, &device, metav1.UpdateOptions{}) + if err != nil { + log.Error(err, "Failed device status update") + } + } + } else if device.Status.NodeName == os.Getenv("NODE_NAME") && !m.isDeviceAvailable(device.Name) { + log.Info("Device unavailable, updating state.") + utils.SetDeviceCondition(&device.Status.Conditions, v1alpha1.DeviceCondition{ + Type: v1alpha1.DeviceAvailable, + Status: metav1.ConditionFalse, + Reason: "DeviceUnavailable", + }) + device.Status.NodeName = "" + _, err := m.devicesClient.UpdateStatus(ctx, &device, metav1.UpdateOptions{}) + if err != nil { + log.Error(err, "Failed device status update") } } } } -func isDeviceAvailable(name string) bool { - if _, err := os.Stat("/dev/tty" + name); os.IsNotExist(err) { +func (m *Monitor) isDeviceAvailable(name string) bool { + if _, err := m.statFile("/dev/tty" + name); os.IsNotExist(err) { return false } return true } -func clearState(ctx context.Context, c *corev1.ConfigMap, client v1.ConfigMapInterface) error { +func (m *Monitor) clearState(ctx context.Context, c *corev1.ConfigMap) error { return retry.RetryOnConflict(retry.DefaultRetry, func() error { c.Data["available"] = "false" c.Data["node"] = "" - _, updateErr := client.Update(ctx, c, metav1.UpdateOptions{}) + _, updateErr := m.cmClient.Update(ctx, c, metav1.UpdateOptions{}) return updateErr }) } -func setActiveState(ctx context.Context, c *corev1.ConfigMap, client v1.ConfigMapInterface) error { +func (m *Monitor) setActiveState(ctx context.Context, c *corev1.ConfigMap) error { return retry.RetryOnConflict(retry.DefaultRetry, func() error { c.Data["available"] = "true" c.Data["node"] = os.Getenv("NODE_NAME") - _, updateErr := client.Update(ctx, c, metav1.UpdateOptions{}) + _, updateErr := m.cmClient.Update(ctx, c, metav1.UpdateOptions{}) return updateErr }) } diff --git a/pkg/monitor/monitor_test.go b/pkg/monitor/monitor_test.go new file mode 100644 index 00000000..91fa194d --- /dev/null +++ b/pkg/monitor/monitor_test.go @@ -0,0 +1,100 @@ +package monitor + +import ( + "context" + "os" + "testing" + + "github.com/janekbaraniewski/kubeserial/pkg/apis/kubeserial/v1alpha1" + "github.com/janekbaraniewski/kubeserial/pkg/generated/clientset/versioned/fake" + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + testclient "k8s.io/client-go/kubernetes/fake" +) + +func TestUpdateDeviceState_ConfigMap(t *testing.T) { + ctx := context.Background() + + cm := &corev1.ConfigMap{ + ObjectMeta: v1.ObjectMeta{ + Name: "test-device-state", + Namespace: "test-ns", + Labels: map[string]string{ + "type": "DeviceState", + }, + }, + Data: map[string]string{ + "available": "false", + }, + } + + fakeClientset := testclient.NewSimpleClientset(cm) + fakeClientsetKubeserial := fake.NewSimpleClientset() + fs := afero.NewMemMapFs() + monitor := NewMonitor(fakeClientset, fakeClientsetKubeserial, "test-ns", fs.Stat) + monitor.UpdateDeviceState(ctx) +} + +func TestUpdateDeviceState_Device(t *testing.T) { + ctx := context.Background() + device := &v1alpha1.Device{ + ObjectMeta: v1.ObjectMeta{ + Name: "test-device", + Namespace: "test-ns", + }, + Spec: v1alpha1.DeviceSpec{ + Name: "test-device", + IdVendor: "123", + IdProduct: "456", + Subsystem: "tty", + Manager: "test-manager", + }, + Status: v1alpha1.DeviceStatus{ + Conditions: []v1alpha1.DeviceCondition{ + { + Type: v1alpha1.DeviceAvailable, + Status: v1.ConditionFalse, + }, + }, + NodeName: "test-node", + }, + } + os.Setenv("NODE_NAME", "test-node") + { + t.Run("test-update-available-condition-when-available", func(t *testing.T) { + fakeClientset := testclient.NewSimpleClientset() + fakeClientsetKubeserial := fake.NewSimpleClientset(device) + fs := afero.NewMemMapFs() + fs.Create("/dev/tty" + device.Name) + monitor := NewMonitor(fakeClientset, fakeClientsetKubeserial, "test-ns", fs.Stat) + + monitor.UpdateDeviceState(ctx) + + foundDevice, err := fakeClientsetKubeserial.AppV1alpha1().Devices("test-ns").Get( + ctx, device.Name, v1.GetOptions{}) + + assert.Equal(t, nil, err) + assert.Equal(t, v1.ConditionTrue, foundDevice.Status.Conditions[0].Status) + }) + } + { + t.Run("test-update-available-condition-when-unavailable", func(t *testing.T) { + device.Status.Conditions[0].Status = v1.ConditionTrue + fakeClientset := testclient.NewSimpleClientset() + fakeClientsetKubeserial := fake.NewSimpleClientset(device) + fs := afero.NewMemMapFs() + monitor := NewMonitor(fakeClientset, fakeClientsetKubeserial, "test-ns", fs.Stat) + + monitor.UpdateDeviceState(ctx) + + foundDevice, err := fakeClientsetKubeserial.AppV1alpha1().Devices("test-ns").Get( + ctx, device.Name, v1.GetOptions{}) + + assert.Equal(t, nil, err) + assert.Equal(t, v1.ConditionFalse, foundDevice.Status.Conditions[0].Status) + }) + } + os.Unsetenv("NODE_NAME") +}