1515package functional
1616
1717import (
18+ "encoding/json"
1819 "fmt"
1920 "io/ioutil"
2021 "os"
@@ -26,6 +27,7 @@ import (
2627
2728 "github.com/coreos/fleet/functional/platform"
2829 "github.com/coreos/fleet/functional/util"
30+ "github.com/coreos/fleet/unit"
2931)
3032
3133const (
@@ -678,3 +680,149 @@ func waitForNUnitsCmd(cl platform.Cluster, m platform.Member, cmd string, nu int
678680// frequently than before, it's a huge pain to make it succeed every time.
679681// The failure brings a negative impact on productivity. So remove the entire
680682// test for now. - dpark 20160829
683+
684+ // TestUnitDestroyFromRegistry() checks for a submitted unit being removed
685+ // from the etcd registry. It compares a local unit body with the unit in
686+ // the etcd registry, to verify the body is identical.
687+ func TestUnitDestroyFromRegistry (t * testing.T ) {
688+ cluster , err := platform .NewNspawnCluster ("smoke" )
689+ if err != nil {
690+ t .Fatal (err )
691+ }
692+ defer cluster .Destroy (t )
693+
694+ m , err := cluster .CreateMember ()
695+ if err != nil {
696+ t .Fatal (err )
697+ }
698+ _ , err = cluster .WaitForNMachines (m , 1 )
699+ if err != nil {
700+ t .Fatal (err )
701+ }
702+
703+ // submit a unit and assert it shows up
704+ if _ , _ , err := cluster .Fleetctl (m , "submit" , "fixtures/units/hello.service" ); err != nil {
705+ t .Fatalf ("Unable to submit fleet unit: %v" , err )
706+ }
707+ stdout , _ , err := cluster .Fleetctl (m , "list-units" , "--no-legend" )
708+ if err != nil {
709+ t .Fatalf ("Failed to run list-units: %v" , err )
710+ }
711+ units := strings .Split (strings .TrimSpace (stdout ), "\n " )
712+ if len (units ) != 1 {
713+ t .Fatalf ("Did not find 1 unit in cluster: \n %s" , stdout )
714+ }
715+
716+ // cat the unit and compare it with the value in etcd registry
717+ unitBody , _ , err := cluster .Fleetctl (m , "cat" , "hello.service" )
718+ if err != nil {
719+ t .Fatalf ("Unable to retrieve the fleet unit: %v" , err )
720+ }
721+
722+ var hashUnit string
723+ if hashUnit , err = retrieveJobObjectHash (cluster , "hello.service" ); err != nil {
724+ t .Fatalf ("Failed to retrieve hash of job object hello.service: %v" , err )
725+ }
726+
727+ var regBody string
728+ if regBody , err = retrieveUnitBody (cluster , hashUnit ); err != nil {
729+ t .Fatalf ("Failed to retrieve unit body for hello.service: %v" , err )
730+ }
731+
732+ // compare it with unitBody
733+ if regBody != unitBody {
734+ t .Fatalf ("Failed to verify fleet unit: %v" , err )
735+ }
736+
737+ // destroy the unit again
738+ if _ , _ , err := cluster .Fleetctl (m , "destroy" , "hello.service" ); err != nil {
739+ t .Fatalf ("Failed to destroy unit: %v" , err )
740+ }
741+
742+ stdout , _ , err = cluster .Fleetctl (m , "list-units" , "--no-legend" )
743+ if err != nil {
744+ t .Fatalf ("Failed to run list-units: %v" , err )
745+ }
746+ units = strings .Split (strings .TrimSpace (stdout ), "\n " )
747+ if len (stdout ) != 0 && len (units ) != 1 {
748+ t .Fatalf ("Did not find 1 unit in cluster: \n %s" , stdout )
749+ }
750+
751+ // check for the unit being destroyed from the etcd registry,
752+ // /fleet_functional/smoke/unit/.
753+ // NOTE: do not check error of etcdctl, as it returns 4 on an empty list.
754+ etcdUnitPrefix := path .Join (cluster .Keyspace (), "unit" )
755+ etcdUnitPath := path .Join (etcdUnitPrefix , hashUnit )
756+ stdout , _ , _ = util .RunEtcdctl ("ls" , etcdUnitPath )
757+ units = strings .Split (strings .TrimSpace (stdout ), "\n " )
758+ if len (stdout ) != 0 && len (units ) != 1 {
759+ t .Fatalf ("The unit still remains in the registry: %v" )
760+ }
761+ }
762+
763+ // retrieveJobObjectHash fetches the job hash value from
764+ // /fleet_functional/smoke/job/<jobName>/object in the etcd registry.
765+ func retrieveJobObjectHash (cluster platform.Cluster , jobName string ) (hash string , err error ) {
766+ etcdJobPrefix := path .Join (cluster .Keyspace (), "job" )
767+ etcdJobPath := path .Join (etcdJobPrefix , jobName , "object" )
768+
769+ var stdout string
770+ if stdout , _ , err = util .RunEtcdctl ("ls" , etcdJobPath ); err != nil {
771+ return "" , fmt .Errorf ("Failed to list a unit from the registry: %v" , err )
772+ }
773+ units := strings .Split (strings .TrimSpace (stdout ), "\n " )
774+ if len (stdout ) == 0 || len (units ) == 0 {
775+ return "" , fmt .Errorf ("No such unit in the registry: %v" , err )
776+ }
777+
778+ stdout , _ , err = util .RunEtcdctl ("get" , etcdJobPath )
779+ stdout = strings .TrimSpace (stdout )
780+ objectBody := strings .Split (stdout , "\n " )
781+ if err != nil || len (stdout ) == 0 || len (objectBody ) == 0 {
782+ return "" , fmt .Errorf ("Failed to get unit from the registry: %v" , err )
783+ }
784+
785+ type jobModel struct {
786+ Name string
787+ UnitHash unit.Hash
788+ }
789+ var jm jobModel
790+ if err = json .Unmarshal ([]byte (stdout ), & jm ); err != nil {
791+ return "" , fmt .Errorf ("Failed to unmarshal fleet unit in the registry: %v" , err )
792+ }
793+
794+ return jm .UnitHash .String (), nil
795+ }
796+
797+ // retrieveUnitBody fetches unit body from /fleet_functional/smoke/unit/<hash>
798+ // in the etcd registry.
799+ func retrieveUnitBody (cluster platform.Cluster , hashUnit string ) (regBody string , err error ) {
800+ etcdUnitPrefix := path .Join (cluster .Keyspace (), "unit" )
801+ etcdUnitPath := path .Join (etcdUnitPrefix , hashUnit )
802+
803+ var stdout string
804+ if stdout , _ , err = util .RunEtcdctl ("ls" , etcdUnitPath ); err != nil {
805+ return "" , fmt .Errorf ("Failed to list a unit from the registry: %v" , err )
806+ }
807+
808+ units := strings .Split (strings .TrimSpace (stdout ), "\n " )
809+ if len (stdout ) == 0 || len (units ) == 0 {
810+ return "" , fmt .Errorf ("No such unit in the registry: %v" , err )
811+ }
812+ stdout , _ , err = util .RunEtcdctl ("get" , etcdUnitPath )
813+ stdout = strings .TrimSpace (stdout )
814+ unitBody := strings .Split (stdout , "\n " )
815+ if err != nil || len (stdout ) == 0 || len (unitBody ) == 0 {
816+ return "" , fmt .Errorf ("Failed to get unit from the registry: %v" , err )
817+ }
818+
819+ type rawModel struct {
820+ Raw string
821+ }
822+
823+ var rm rawModel
824+ if err = json .Unmarshal ([]byte (stdout ), & rm ); err != nil {
825+ return "" , fmt .Errorf ("Failed to unmarshal fleet unit in the registry: %v" , err )
826+ }
827+ return rm .Raw , nil
828+ }
0 commit comments