@@ -14,6 +14,12 @@ const APIVersion = 2
14
14
15
15
const streamNotConfiguredCode = "StreamNotConfigured"
16
16
17
+ // Stream is a stream context parameter.
18
+ const Stream = true
19
+
20
+ // HTTP is a HTTP context parameter.
21
+ const HTTP = false
22
+
17
23
// NginxClient lets you access NGINX Plus API.
18
24
type NginxClient struct {
19
25
apiEndpoint string
@@ -778,3 +784,244 @@ func (client *NginxClient) getStreamUpstreams() (*StreamUpstreams, error) {
778
784
}
779
785
return & upstreams , nil
780
786
}
787
+
788
+ // KeyValPairs are the key-value pairs stored in a zone.
789
+ type KeyValPairs map [string ]string
790
+
791
+ // KeyValPairsByZone are the KeyValPairs for all zones, by zone name.
792
+ type KeyValPairsByZone map [string ]KeyValPairs
793
+
794
+ // GetKeyValPairs fetches key/value pairs for a given zone.
795
+ func (client * NginxClient ) GetKeyValPairs (zone string ) (KeyValPairs , error ) {
796
+ return client .getKeyValPairs (zone , HTTP )
797
+ }
798
+
799
+ // GetStreamKeyValPairs fetches key/value pairs for a given zone.
800
+ func (client * NginxClient ) GetStreamKeyValPairs (zone string ) (KeyValPairs , error ) {
801
+ return client .getKeyValPairs (zone , Stream )
802
+ }
803
+
804
+ func (client * NginxClient ) getKeyValPairs (zone string , stream bool ) (KeyValPairs , error ) {
805
+ keyvals := make (map [string ]string )
806
+ base := "http"
807
+ if stream {
808
+ base = "stream"
809
+ }
810
+ if zone == "" {
811
+ return nil , fmt .Errorf ("zone required" )
812
+ }
813
+ err := client .get (fmt .Sprintf ("%v/keyvals/%v" , base , zone ), & keyvals )
814
+ if err != nil {
815
+ return nil , fmt .Errorf ("failed to get keyvals for zone: %v/%v: %v" , base , zone , err )
816
+ }
817
+ return keyvals , nil
818
+ }
819
+
820
+ // GetAllKeyValPairs fetches all key/value pairs for all zones.
821
+ func (client * NginxClient ) GetAllKeyValPairs () (KeyValPairsByZone , error ) {
822
+ return client .getAllKeyValPairs (HTTP )
823
+ }
824
+
825
+ // GetStreamAllKeyValPairs fetches all key/value pairs for all zones.
826
+ func (client * NginxClient ) GetStreamAllKeyValPairs () (KeyValPairsByZone , error ) {
827
+ return client .getAllKeyValPairs (Stream )
828
+ }
829
+
830
+ func (client * NginxClient ) getAllKeyValPairs (stream bool ) (KeyValPairsByZone , error ) {
831
+ // keyvals := make(map[string]map[string]string)
832
+ var keyvals KeyValPairsByZone
833
+ base := "http"
834
+ if stream {
835
+ base = "stream"
836
+ }
837
+ err := client .get (fmt .Sprintf ("%v/keyvals" , base ), & keyvals )
838
+ if err != nil {
839
+ return nil , fmt .Errorf ("failed to get keyvals for all %v zones: %v" , base , err )
840
+ }
841
+ return keyvals , nil
842
+ }
843
+
844
+ // AddKeyValPair adds a new key/value pair.
845
+ func (client * NginxClient ) AddKeyValPair (zone string , keyval KeyValPairs ) error {
846
+ return client .addKeyValPair (zone , keyval , HTTP )
847
+ }
848
+
849
+ // AddStreamKeyValPair adds a new key/value pair.
850
+ func (client * NginxClient ) AddStreamKeyValPair (zone string , keyval KeyValPairs ) error {
851
+ return client .addKeyValPair (zone , keyval , Stream )
852
+ }
853
+
854
+ func (client * NginxClient ) addKeyValPair (zone string , keyval KeyValPairs , stream bool ) error {
855
+ base := "http"
856
+ if stream {
857
+ base = "stream"
858
+ }
859
+ path := fmt .Sprintf ("%v/keyvals" , base )
860
+ url := fmt .Sprintf ("%v/%v/%v" , client .apiEndpoint , APIVersion , path )
861
+ if zone != "" {
862
+ url = fmt .Sprintf ("%v/%v" , url , zone )
863
+ } else {
864
+ return fmt .Errorf ("zone required" )
865
+ }
866
+
867
+ jsonInput , err := json .Marshal (keyval )
868
+ if err != nil {
869
+ return fmt .Errorf ("failed to marshall input: %v" , err )
870
+ }
871
+
872
+ resp , err := client .httpClient .Post (url , "application/json" , bytes .NewBuffer (jsonInput ))
873
+ if err != nil {
874
+ return fmt .Errorf ("failed to create post request: %v" , err )
875
+ }
876
+ defer resp .Body .Close ()
877
+
878
+ if resp .StatusCode != http .StatusCreated {
879
+ return createResponseMismatchError (resp .Body ).Wrap (fmt .Sprintf (
880
+ "expected %v response, got %v" ,
881
+ http .StatusCreated , resp .StatusCode ))
882
+ }
883
+ return nil
884
+ }
885
+
886
+ // ModifyKeyValPair modifies the value of an existing key.
887
+ func (client * NginxClient ) ModifyKeyValPair (zone string , keyval KeyValPairs ) error {
888
+ return client .modifyKeyValPair (zone , keyval , HTTP )
889
+ }
890
+
891
+ // ModifyStreamKeyValPair modifies the value of an existing key.
892
+ func (client * NginxClient ) ModifyStreamKeyValPair (zone string , keyval KeyValPairs ) error {
893
+ return client .modifyKeyValPair (zone , keyval , Stream )
894
+ }
895
+
896
+ func (client * NginxClient ) modifyKeyValPair (zone string , keyval KeyValPairs , stream bool ) error {
897
+ base := "http"
898
+ if stream {
899
+ base = "stream"
900
+ }
901
+ path := fmt .Sprintf ("%v/keyvals" , base )
902
+ url := fmt .Sprintf ("%v/%v/%v" , client .apiEndpoint , APIVersion , path )
903
+ if zone != "" {
904
+ url = fmt .Sprintf ("%v/%v" , url , zone )
905
+ } else {
906
+ return fmt .Errorf ("zone required" )
907
+ }
908
+
909
+ jsonInput , err := json .Marshal (keyval )
910
+ if err != nil {
911
+ return fmt .Errorf ("failed to marshall input: %v" , err )
912
+ }
913
+ req , err := http .NewRequest (http .MethodPatch , url , bytes .NewBuffer (jsonInput ))
914
+ if err != nil {
915
+ return fmt .Errorf ("failed to create a patch request: %v" , err )
916
+ }
917
+ req .Header .Set ("Content-Type" , "application/json" )
918
+
919
+ resp , err := client .httpClient .Do (req )
920
+ if err != nil {
921
+ return fmt .Errorf ("failed to do patch request: %v" , err )
922
+ }
923
+ defer resp .Body .Close ()
924
+ // We will consider ONLY 204 as success
925
+ if resp .StatusCode != http .StatusNoContent {
926
+ return createResponseMismatchError (resp .Body ).Wrap (fmt .Sprintf (
927
+ "expected %v response, got %v" ,
928
+ http .StatusNoContent , resp .StatusCode ))
929
+ }
930
+ return nil
931
+ }
932
+
933
+ // DeleteKeyValuePair deletes the key/value pair for a given key.
934
+ func (client * NginxClient ) DeleteKeyValuePair (zone string , key string ) error {
935
+ return client .deleteKeyValuePair (zone , key , HTTP )
936
+ }
937
+
938
+ // DeleteStreamKeyValuePair deletes the key/value pair for a given key.
939
+ func (client * NginxClient ) DeleteStreamKeyValuePair (zone string , key string ) error {
940
+ return client .deleteKeyValuePair (zone , key , Stream )
941
+ }
942
+
943
+ // To delete a key/value pair you set the value to null via the API,
944
+ // then NGINX+ will delete the key.
945
+ func (client * NginxClient ) deleteKeyValuePair (zone string , key string , stream bool ) error {
946
+ base := "http"
947
+ if stream {
948
+ base = "stream"
949
+ }
950
+ path := fmt .Sprintf ("%v/keyvals" , base )
951
+ url := fmt .Sprintf ("%v/%v/%v" , client .apiEndpoint , APIVersion , path )
952
+ if zone != "" {
953
+ url = fmt .Sprintf ("%v/%v" , url , zone )
954
+ } else {
955
+ return fmt .Errorf ("zone required" )
956
+ }
957
+
958
+ // map[string]string can't have a nil value so we use a different type here.
959
+ keyval := make (map [string ]interface {})
960
+ keyval [key ] = nil
961
+
962
+ jsonInput , err := json .Marshal (keyval )
963
+ if err != nil {
964
+ return fmt .Errorf ("failed to marshall input: %v" , err )
965
+ }
966
+
967
+ req , err := http .NewRequest (http .MethodPatch , url , bytes .NewBuffer (jsonInput ))
968
+ if err != nil {
969
+ return fmt .Errorf ("failed to create a patch request: %v" , err )
970
+ }
971
+ req .Header .Set ("Content-Type" , "application/json" )
972
+
973
+ resp , err := client .httpClient .Do (req )
974
+ if err != nil {
975
+ return fmt .Errorf ("failed to do patch request: %v" , err )
976
+ }
977
+ defer resp .Body .Close ()
978
+
979
+ // Expect status 204
980
+ if resp .StatusCode != http .StatusNoContent {
981
+ return createResponseMismatchError (resp .Body ).Wrap (fmt .Sprintf (
982
+ "expected %v response, got %v" ,
983
+ http .StatusNoContent , resp .StatusCode ))
984
+ }
985
+ return nil
986
+ }
987
+
988
+ // DeleteKeyValuePairs deletes all the key-value pairs in a given zone.
989
+ func (client * NginxClient ) DeleteKeyValuePairs (zone string ) error {
990
+ return client .deleteKeyValPairs (zone , HTTP )
991
+ }
992
+
993
+ // DeleteStreamKeyValuePairs deletes all the key-value pairs in a given zone.
994
+ func (client * NginxClient ) DeleteStreamKeyValuePairs (zone string ) error {
995
+ return client .deleteKeyValPairs (zone , Stream )
996
+ }
997
+
998
+ func (client * NginxClient ) deleteKeyValPairs (zone string , stream bool ) error {
999
+ base := "http"
1000
+ if stream {
1001
+ base = "stream"
1002
+ }
1003
+ if zone == "" {
1004
+ return fmt .Errorf ("zone required" )
1005
+ }
1006
+ path := fmt .Sprintf ("%v/keyvals/%v" , base , zone )
1007
+ url := fmt .Sprintf ("%v/%v/%v" , client .apiEndpoint , APIVersion , path )
1008
+
1009
+ req , err := http .NewRequest (http .MethodDelete , url , nil )
1010
+ if err != nil {
1011
+ return fmt .Errorf ("failed to create a delete request: %v" , err )
1012
+ }
1013
+
1014
+ resp , err := client .httpClient .Do (req )
1015
+ if err != nil {
1016
+ return fmt .Errorf ("failed to do delete request: %v" , err )
1017
+ }
1018
+ defer resp .Body .Close ()
1019
+
1020
+ // expect status 204
1021
+ if resp .StatusCode != http .StatusNoContent {
1022
+ return createResponseMismatchError (resp .Body ).Wrap (fmt .Sprintf (
1023
+ "expected %v response, got %v" ,
1024
+ http .StatusNoContent , resp .StatusCode ))
1025
+ }
1026
+ return nil
1027
+ }
0 commit comments