blob: cc619576ecdf15c6605e3bf9880347eccf17c403 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
import logging, json, os
import openserverless.redis as redis
import openserverless.util as util
import openserverless.kube as kube
import openserverless.template as ntp
class RedisClient:
"""
Simple Redis Client Used by the quota cheker
"""
def __init__(self, redis_password: str):
redis.wait_for_redis_ready()
self._data = {
"name": "redis",
"container": "redis",
"redis_password": redis_password
}
self.prepare_scripts()
def prepare_scripts(self):
"""
Prepare the initial script to be used to interact with REDIS
"""
logging.info("***** uploading REDIS quota scripts *****")
self._data['path_to_lua_script']= self.render_script("redis_quota_checker.lua",self._data)
self._data['path_to_script'] = self.render_script("redis_quota_checker.sh",self._data)
self._data['pod_name'] = util.get_pod_name("{.items[?(@.metadata.labels.name == 'redis')].metadata.name}")
kube.kubectl("cp",self._data['path_to_lua_script'],f"{self._data['pod_name']}:{self._data['path_to_lua_script']}")
kube.kubectl("cp",self._data['path_to_script'],f"{self._data['pod_name']}:{self._data['path_to_script']}")
kube.kubectl("exec","-it",self._data['pod_name'],"--","/bin/bash","-c",f"chmod 700 {self._data['path_to_script']}")
logging.info("***** uploading REDIS quota scripts completed *****")
def render_script(self, template,data):
"""
uses the given template to render a redis-cli script to be executed.
"""
out = f"/tmp/__{template}"
file = ntp.spool_template(template, out, data)
return os.path.abspath(file)
def exec_lua_script(self, prefix):
"""
Eecute a Lua script
"""
logging.info("executing script %s on pod %s", self._data['path_to_script'], self._data['pod_name'])
res = kube.kubectl("exec","-it",self._data['pod_name'],"--","/bin/bash","-c",f"{self._data['path_to_script']} {prefix}")
return res
def calculate_prefix_allocated_size(self, prefix):
"""
Evaluate a LUA script to calculate the prefix allocated size in bytes
"""
logging.info("checking redis/valkey allocated size with prefix %s", prefix)
try:
prefix_allocated_size = self.exec_lua_script(prefix)
logging.info("prefix %s calculated size=%s", prefix, prefix_allocated_size)
if "(integer)" in prefix_allocated_size:
return int(prefix_allocated_size.replace("(integer)",""))
else:
return int(prefix_allocated_size)
except Exception as e:
logging.error("failed to check redis/valkey allocated size for prefix %s %s", prefix, e)
return None
def set_prefix_readonly(self, namespace, prefix):
"""
Submit the redis script to revoke namespace write rights on the given prefix
"""
self._data['prefix']=prefix
self._data['namespace']=namespace
self._data['mode']='readonly'
logging.info("setting redis/valkey %s with @READ ACL", prefix)
try:
redis.wait_for_redis_ready()
path_to_script = redis.render_redis_script(namespace,"redis_manage_user_tpl.txt",self._data)
pod_name = util.get_pod_name("{.items[?(@.metadata.labels.name == 'redis')].metadata.name}")
if(pod_name):
res = redis.exec_redis_command(pod_name,path_to_script)
return res
return None
except Exception as e:
logging.error("failed to set redis/valkey %s with @READ ACL: %s", prefix, e)
return None
def set_prefix_all(self, namespace, prefix):
"""
Submit the redis script to re-enable namespace write rights on the given prefix
"""
self._data['prefix']=prefix
self._data['namespace']=namespace
self._data['mode']='readandwrite'
logging.info("setting redis/valkey %s with +@ALL ACL", prefix)
try:
redis.wait_for_redis_ready()
path_to_script = redis.render_redis_script(namespace,"redis_manage_user_tpl.txt",self._data)
pod_name = util.get_pod_name("{.items[?(@.metadata.labels.name == 'redis')].metadata.name}")
if(pod_name):
res = redis.exec_redis_command(pod_name,path_to_script)
return res
return None
except Exception as e:
logging.error("failed to set redis/valkey %s with +@ALL ACL: %s", prefix, e)
return None