@@ -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
@@ -806,3 +812,243 @@ func (client *NginxClient) getStreamUpstreams() (*StreamUpstreams, error) {
806
812
}
807
813
return & upstreams , nil
808
814
}
815
+
816
+ // KeyValPairs are the key-value pairs stored in a zone.
817
+ type KeyValPairs map [string ]string
818
+
819
+ // KeyValPairsByZone are the KeyValPairs for all zones, by zone name.
820
+ type KeyValPairsByZone map [string ]KeyValPairs
821
+
822
+ // GetKeyValPairs fetches key/value pairs for a given HTTP zone.
823
+ func (client * NginxClient ) GetKeyValPairs (zone string ) (KeyValPairs , error ) {
824
+ return client .getKeyValPairs (zone , HTTP )
825
+ }
826
+
827
+ // GetStreamKeyValPairs fetches key/value pairs for a given Stream zone.
828
+ func (client * NginxClient ) GetStreamKeyValPairs (zone string ) (KeyValPairs , error ) {
829
+ return client .getKeyValPairs (zone , Stream )
830
+ }
831
+
832
+ func (client * NginxClient ) getKeyValPairs (zone string , stream bool ) (KeyValPairs , error ) {
833
+ base := "http"
834
+ if stream {
835
+ base = "stream"
836
+ }
837
+ if zone == "" {
838
+ return nil , fmt .Errorf ("zone required" )
839
+ }
840
+ var keyValPairs KeyValPairs
841
+ err := client .get (fmt .Sprintf ("%v/keyvals/%v" , base , zone ), & keyValPairs )
842
+ if err != nil {
843
+ return nil , fmt .Errorf ("failed to get keyvals for zone: %v/%v: %v" , base , zone , err )
844
+ }
845
+ return keyValPairs , nil
846
+ }
847
+
848
+ // GetAllKeyValPairs fetches all key/value pairs for all HTTP zones.
849
+ func (client * NginxClient ) GetAllKeyValPairs () (KeyValPairsByZone , error ) {
850
+ return client .getAllKeyValPairs (HTTP )
851
+ }
852
+
853
+ // GetAllStreamKeyValPairs fetches all key/value pairs for all Stream zones.
854
+ func (client * NginxClient ) GetAllStreamKeyValPairs () (KeyValPairsByZone , error ) {
855
+ return client .getAllKeyValPairs (Stream )
856
+ }
857
+
858
+ func (client * NginxClient ) getAllKeyValPairs (stream bool ) (KeyValPairsByZone , error ) {
859
+ base := "http"
860
+ if stream {
861
+ base = "stream"
862
+ }
863
+ var keyValPairsByZone KeyValPairsByZone
864
+ err := client .get (fmt .Sprintf ("%v/keyvals" , base ), & keyValPairsByZone )
865
+ if err != nil {
866
+ return nil , fmt .Errorf ("failed to get keyvals for all %v zones: %v" , base , err )
867
+ }
868
+ return keyValPairsByZone , nil
869
+ }
870
+
871
+ // AddKeyValPair adds a new key/value pair to a given HTTP zone.
872
+ func (client * NginxClient ) AddKeyValPair (zone string , key string , val string ) error {
873
+ return client .addKeyValPair (zone , key , val , HTTP )
874
+ }
875
+
876
+ // AddStreamKeyValPair adds a new key/value pair to a given Stream zone.
877
+ func (client * NginxClient ) AddStreamKeyValPair (zone string , key string , val string ) error {
878
+ return client .addKeyValPair (zone , key , val , Stream )
879
+ }
880
+
881
+ func (client * NginxClient ) addKeyValPair (zone string , key string , val string , stream bool ) error {
882
+ base := "http"
883
+ if stream {
884
+ base = "stream"
885
+ }
886
+ path := fmt .Sprintf ("%v/keyvals" , base )
887
+ url := fmt .Sprintf ("%v/%v/%v" , client .apiEndpoint , APIVersion , path )
888
+ if zone != "" {
889
+ url = fmt .Sprintf ("%v/%v" , url , zone )
890
+ } else {
891
+ return fmt .Errorf ("zone required" )
892
+ }
893
+
894
+ jsonInput , err := json .Marshal (KeyValPairs {key : val })
895
+ if err != nil {
896
+ return fmt .Errorf ("failed to marshall input: %v" , err )
897
+ }
898
+
899
+ resp , err := client .httpClient .Post (url , "application/json" , bytes .NewBuffer (jsonInput ))
900
+ if err != nil {
901
+ return fmt .Errorf ("failed to create post request: %v" , err )
902
+ }
903
+ defer resp .Body .Close ()
904
+
905
+ if resp .StatusCode != http .StatusCreated {
906
+ return createResponseMismatchError (resp .Body ).Wrap (fmt .Sprintf (
907
+ "expected %v response, got %v" ,
908
+ http .StatusCreated , resp .StatusCode ))
909
+ }
910
+ return nil
911
+ }
912
+
913
+ // ModifyKeyValPair modifies the value of an existing key in a given HTTP zone.
914
+ func (client * NginxClient ) ModifyKeyValPair (zone string , key string , val string ) error {
915
+ return client .modifyKeyValPair (zone , key , val , HTTP )
916
+ }
917
+
918
+ // ModifyStreamKeyValPair modifies the value of an existing key in a given Stream zone.
919
+ func (client * NginxClient ) ModifyStreamKeyValPair (zone string , key string , val string ) error {
920
+ return client .modifyKeyValPair (zone , key , val , Stream )
921
+ }
922
+
923
+ func (client * NginxClient ) modifyKeyValPair (zone string , key string , val string , stream bool ) error {
924
+ base := "http"
925
+ if stream {
926
+ base = "stream"
927
+ }
928
+ path := fmt .Sprintf ("%v/keyvals" , base )
929
+ url := fmt .Sprintf ("%v/%v/%v" , client .apiEndpoint , APIVersion , path )
930
+ if zone != "" {
931
+ url = fmt .Sprintf ("%v/%v" , url , zone )
932
+ } else {
933
+ return fmt .Errorf ("zone required" )
934
+ }
935
+
936
+ jsonInput , err := json .Marshal (KeyValPairs {key : val })
937
+ if err != nil {
938
+ return fmt .Errorf ("failed to marshall input: %v" , err )
939
+ }
940
+ req , err := http .NewRequest (http .MethodPatch , url , bytes .NewBuffer (jsonInput ))
941
+ if err != nil {
942
+ return fmt .Errorf ("failed to create a patch request: %v" , err )
943
+ }
944
+ req .Header .Set ("Content-Type" , "application/json" )
945
+
946
+ resp , err := client .httpClient .Do (req )
947
+ if err != nil {
948
+ return fmt .Errorf ("failed to do patch request: %v" , err )
949
+ }
950
+ defer resp .Body .Close ()
951
+ // We will consider ONLY 204 as success
952
+ if resp .StatusCode != http .StatusNoContent {
953
+ return createResponseMismatchError (resp .Body ).Wrap (fmt .Sprintf (
954
+ "expected %v response, got %v" ,
955
+ http .StatusNoContent , resp .StatusCode ))
956
+ }
957
+ return nil
958
+ }
959
+
960
+ // DeleteKeyValuePair deletes the key/value pair for a given key.
961
+ func (client * NginxClient ) DeleteKeyValuePair (zone string , key string ) error {
962
+ return client .deleteKeyValuePair (zone , key , HTTP )
963
+ }
964
+
965
+ // DeleteStreamKeyValuePair deletes the key/value pair for a given key.
966
+ func (client * NginxClient ) DeleteStreamKeyValuePair (zone string , key string ) error {
967
+ return client .deleteKeyValuePair (zone , key , Stream )
968
+ }
969
+
970
+ // To delete a key/value pair you set the value to null via the API,
971
+ // then NGINX+ will delete the key.
972
+ func (client * NginxClient ) deleteKeyValuePair (zone string , key string , stream bool ) error {
973
+ base := "http"
974
+ if stream {
975
+ base = "stream"
976
+ }
977
+ path := fmt .Sprintf ("%v/keyvals" , base )
978
+ url := fmt .Sprintf ("%v/%v/%v" , client .apiEndpoint , APIVersion , path )
979
+ if zone != "" {
980
+ url = fmt .Sprintf ("%v/%v" , url , zone )
981
+ } else {
982
+ return fmt .Errorf ("zone required" )
983
+ }
984
+
985
+ // map[string]string can't have a nil value so we use a different type here.
986
+ keyval := make (map [string ]interface {})
987
+ keyval [key ] = nil
988
+
989
+ jsonInput , err := json .Marshal (keyval )
990
+ if err != nil {
991
+ return fmt .Errorf ("failed to marshall input: %v" , err )
992
+ }
993
+
994
+ req , err := http .NewRequest (http .MethodPatch , url , bytes .NewBuffer (jsonInput ))
995
+ if err != nil {
996
+ return fmt .Errorf ("failed to create a patch request: %v" , err )
997
+ }
998
+ req .Header .Set ("Content-Type" , "application/json" )
999
+
1000
+ resp , err := client .httpClient .Do (req )
1001
+ if err != nil {
1002
+ return fmt .Errorf ("failed to do patch request: %v" , err )
1003
+ }
1004
+ defer resp .Body .Close ()
1005
+
1006
+ // Expect status 204
1007
+ if resp .StatusCode != http .StatusNoContent {
1008
+ return createResponseMismatchError (resp .Body ).Wrap (fmt .Sprintf (
1009
+ "expected %v response, got %v" ,
1010
+ http .StatusNoContent , resp .StatusCode ))
1011
+ }
1012
+ return nil
1013
+ }
1014
+
1015
+ // DeleteKeyValPairs deletes all the key-value pairs in a given HTTP zone.
1016
+ func (client * NginxClient ) DeleteKeyValPairs (zone string ) error {
1017
+ return client .deleteKeyValPairs (zone , HTTP )
1018
+ }
1019
+
1020
+ // DeleteStreamKeyValPairs deletes all the key-value pairs in a given Stream zone.
1021
+ func (client * NginxClient ) DeleteStreamKeyValPairs (zone string ) error {
1022
+ return client .deleteKeyValPairs (zone , Stream )
1023
+ }
1024
+
1025
+ func (client * NginxClient ) deleteKeyValPairs (zone string , stream bool ) error {
1026
+ base := "http"
1027
+ if stream {
1028
+ base = "stream"
1029
+ }
1030
+ if zone == "" {
1031
+ return fmt .Errorf ("zone required" )
1032
+ }
1033
+ path := fmt .Sprintf ("%v/keyvals/%v" , base , zone )
1034
+ url := fmt .Sprintf ("%v/%v/%v" , client .apiEndpoint , APIVersion , path )
1035
+
1036
+ req , err := http .NewRequest (http .MethodDelete , url , nil )
1037
+ if err != nil {
1038
+ return fmt .Errorf ("failed to create a delete request: %v" , err )
1039
+ }
1040
+
1041
+ resp , err := client .httpClient .Do (req )
1042
+ if err != nil {
1043
+ return fmt .Errorf ("failed to do delete request: %v" , err )
1044
+ }
1045
+ defer resp .Body .Close ()
1046
+
1047
+ // expect status 204
1048
+ if resp .StatusCode != http .StatusNoContent {
1049
+ return createResponseMismatchError (resp .Body ).Wrap (fmt .Sprintf (
1050
+ "expected %v response, got %v" ,
1051
+ http .StatusNoContent , resp .StatusCode ))
1052
+ }
1053
+ return nil
1054
+ }
0 commit comments