add resource limits and requests (#63)

* add resource limits and requests
* add validate function

diff --git a/docs/java-agent-injector.md b/docs/java-agent-injector.md
index 7521f12..495d78e 100644
--- a/docs/java-agent-injector.md
+++ b/docs/java-agent-injector.md
@@ -158,7 +158,9 @@
 | `sidecar.skywalking.apache.org/initcontainer.Image`          | The container image of the injected java agent container.    | `apache/skywalking-java-agent:8.8.0-java8`                    |
 | `sidecar.skywalking.apache.org/initcontainer.Command`        | The command of the injected java agent container.            | `sh`                                                         |
 | `sidecar.skywalking.apache.org/initcontainer.args.Option`    | The args option of the injected java agent container.       | `-c`                                                         |
-| `sidecar.skywalking.apache.org/initcontainer.args.Command`   | The args command of  the injected java agent container.      | `mkdir -p /sky/agent && cp -r /skywalking/agent/* /sky/agent` |
+| `sidecar.skywalking.apache.org/initcontainer.args.Command`   | The args command of the injected java agent container.       | `mkdir -p /sky/agent && cp -r /skywalking/agent/* /sky/agent` |
+| `sidecar.skywalking.apache.org/initcontainer.resources.limits`   | The resources limits of the injected java agent container. You should use json type to define it such as `{"memory": "100Mi","cpu": "100m"}`      | `nil` |
+| `sidecar.skywalking.apache.org/initcontainer.resources.requests`   | The resources requests of  the injected java agent container. You should use json type to define it such as `{"memory": "100Mi","cpu": "100m"}`      | `nil` |
 | `sidecar.skywalking.apache.org/sidecarVolume.Name`           | The name of sidecar Volume.                                  | `sky-agent`                                                  |
 | `sidecar.skywalking.apache.org/sidecarVolumeMount.MountPath` | Mount path of the agent directory in the injected container. | `/sky/agent`                                                 |
 | `sidecar.skywalking.apache.org/configmapVolume.Name`         | The name of configmap volume.                                | `java-agent-configmap-volume`                                |
diff --git a/operator/config/samples/default.yaml b/operator/config/samples/default.yaml
index 9e5feb8..f2f0919 100644
--- a/operator/config/samples/default.yaml
+++ b/operator/config/samples/default.yaml
@@ -36,7 +36,7 @@
   version: 8.8.1
   instances: 1
   image: apache/skywalking-ui:8.8.1
-  OAPServerAddress: http://default-oap:12800
+  OAPServerAddress: http://default-oap.default:12800
   service:
     template:
       type: ClusterIP
diff --git a/operator/pkg/operator/injector/injector.go b/operator/pkg/operator/injector/injector.go
index a03f40e..700b06a 100644
--- a/operator/pkg/operator/injector/injector.go
+++ b/operator/pkg/operator/injector/injector.go
@@ -19,6 +19,7 @@
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"strings"
 
@@ -228,20 +229,25 @@
 	s.ConfigmapVolume.ConfigMap = new(corev1.ConfigMapVolumeSource)
 	s.Initcontainer.Command = make([]string, 1)
 	s.Initcontainer.Args = make([]string, 2)
+
+	limitsStr := ""
+	requestStr := ""
 	// every annotation map a pointer to the field of SidecarInjectField
 	annoField := map[string]*string{
-		"initcontainer.Name":             &s.Initcontainer.Name,
-		"initcontainer.Image":            &s.Initcontainer.Image,
-		"initcontainer.Command":          &s.Initcontainer.Command[0],
-		"initcontainer.args.Option":      &s.Initcontainer.Args[0],
-		"initcontainer.args.Command":     &s.Initcontainer.Args[1],
-		"sidecarVolume.Name":             &s.SidecarVolume.Name,
-		"sidecarVolumeMount.MountPath":   &s.SidecarVolumeMount.MountPath,
-		"configmapVolume.ConfigMap.Name": &s.ConfigmapVolume.ConfigMap.Name,
-		"configmapVolume.Name":           &s.ConfigmapVolume.Name,
-		"configmapVolumeMount.MountPath": &s.ConfigmapVolumeMount.MountPath,
-		"env.Name":                       &s.Env.Name,
-		"env.Value":                      &s.Env.Value,
+		"initcontainer.Name":               &s.Initcontainer.Name,
+		"initcontainer.Image":              &s.Initcontainer.Image,
+		"initcontainer.Command":            &s.Initcontainer.Command[0],
+		"initcontainer.args.Option":        &s.Initcontainer.Args[0],
+		"initcontainer.args.Command":       &s.Initcontainer.Args[1],
+		"initcontainer.resources.limits":   &limitsStr,
+		"initcontainer.resources.requests": &requestStr,
+		"sidecarVolume.Name":               &s.SidecarVolume.Name,
+		"sidecarVolumeMount.MountPath":     &s.SidecarVolumeMount.MountPath,
+		"configmapVolume.ConfigMap.Name":   &s.ConfigmapVolume.ConfigMap.Name,
+		"configmapVolume.Name":             &s.ConfigmapVolume.Name,
+		"configmapVolumeMount.MountPath":   &s.ConfigmapVolumeMount.MountPath,
+		"env.Name":                         &s.Env.Name,
+		"env.Value":                        &s.Env.Value,
 	}
 	anno := GetAnnotationsByPrefix(a, sidecarAnnotationPrefix)
 	for _, v := range anno.Annotations {
@@ -252,10 +258,32 @@
 			}
 		}
 	}
+
 	s.SidecarVolumeMount.Name = s.SidecarVolume.Name
 	s.ConfigmapVolumeMount.Name = s.ConfigmapVolume.Name
 	s.Initcontainer.VolumeMounts = []corev1.VolumeMount{s.SidecarVolumeMount}
 
+	// add requests and limits to initcontainer
+	if limitsStr != "nil" {
+		limits := make(corev1.ResourceList)
+		err := json.Unmarshal([]byte(limitsStr), &limits)
+		if err != nil {
+			log.Error(err, "unmarshal limitsStr error")
+			return false
+		}
+		s.Initcontainer.Resources.Limits = limits
+	}
+
+	if requestStr != "nil" {
+		requests := make(corev1.ResourceList)
+		err := json.Unmarshal([]byte(requestStr), &requests)
+		if err != nil {
+			log.Error(err, "unmarshal requestStr error")
+			return false
+		}
+		s.Initcontainer.Resources.Requests = requests
+	}
+
 	// the sidecar volume's type is determined
 	s.SidecarVolume.VolumeSource.EmptyDir = nil
 
diff --git a/operator/pkg/operator/injector/validate.go b/operator/pkg/operator/injector/validate.go
index 102e330..f8e302d 100644
--- a/operator/pkg/operator/injector/validate.go
+++ b/operator/pkg/operator/injector/validate.go
@@ -18,12 +18,16 @@
 package injector
 
 import (
+	"encoding/json"
 	"fmt"
 	"net"
 	"reflect"
 	"regexp"
 	"runtime"
 	"strings"
+
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/util/sets"
 )
 
 // AnnotationValidateFunc is the type of validate function
@@ -35,9 +39,27 @@
 		ValidateServiceName,
 		ValidateBackendServices,
 		ValidateIPv4OrHostname,
+		ValidateResourceRequirements,
 	}
 )
 
+const (
+	// CPU is in cores (100m = .1 cores)
+	CPU string = "cpu"
+	// Memory is in bytes (100Gi = 100GiB = 100 * 1024 * 1024 * 1024)
+	Memory string = "memory"
+	// EphemeralStorage is in bytes (100Gi = 100GiB = 100 * 1024 * 1024 * 1024)
+	EphemeralStorage string = "ephemeral-storage"
+	// HugePagesPrefix is huge pages prefix
+	HugePagesPrefix string = "hugepages-"
+)
+
+var standardContainerResources = sets.NewString(
+	CPU,
+	Memory,
+	EphemeralStorage,
+)
+
 // FindValidateFunc is find the validate function for an annotation
 func FindValidateFunc(funcName string) AnnotationValidateFunc {
 	for _, f := range AnnotationValidateFuncs {
@@ -114,3 +136,30 @@
 
 	return nil
 }
+
+//ValidateResourceRequirements validates the resource requirement
+func ValidateResourceRequirements(annotation, value string) error {
+	if value == "nil" {
+		return nil
+	}
+
+	resource := make(corev1.ResourceList)
+	err := json.Unmarshal([]byte(value), &resource)
+	if err != nil {
+		return fmt.Errorf("%s unmarshal error:%s", annotation, err.Error())
+	}
+
+	for resourceName, quantity := range resource {
+		//validate resource name
+		if !standardContainerResources.Has(string(resourceName)) && !strings.HasPrefix(string(resourceName), HugePagesPrefix) {
+			return fmt.Errorf("%s error:%s isn't a standard resource type", annotation, string(resourceName))
+		}
+
+		//validate resource quantity value
+		if quantity.MilliValue() <= int64(0) {
+			return fmt.Errorf("%s error:%d must be greater than 0", annotation, quantity.MilliValue())
+		}
+	}
+
+	return nil
+}
diff --git a/operator/pkg/operator/manifests/injector/templates/annotations.yaml b/operator/pkg/operator/manifests/injector/templates/annotations.yaml
index 52b31fd..46680fd 100644
--- a/operator/pkg/operator/manifests/injector/templates/annotations.yaml
+++ b/operator/pkg/operator/manifests/injector/templates/annotations.yaml
@@ -48,6 +48,16 @@
     defaultValue: "mkdir -p /sky/agent && cp -r /skywalking/agent/* /sky/agent"
     validateFunc: nil
     envName: nil
+  
+  - name: sidecar.skywalking.apache.org/initcontainer.resources.limits
+    defaultValue: nil
+    validateFunc: ValidateResourceRequirements
+    envName: nil
+
+  - name: sidecar.skywalking.apache.org/initcontainer.resources.requests
+    defaultValue: nil
+    validateFunc: ValidateResourceRequirements
+    envName: nil
 
   - name: sidecar.skywalking.apache.org/sidecarVolume.Name
     defaultValue: sky-agent
diff --git a/operator/pkg/operator/repo/assets.gen.go b/operator/pkg/operator/repo/assets.gen.go
index 3f0dc37..e8da2fb 100644
--- a/operator/pkg/operator/repo/assets.gen.go
+++ b/operator/pkg/operator/repo/assets.gen.go
@@ -21,7 +21,7 @@
 // fetcher/templates/configmap.yaml (3.082kB)
 // fetcher/templates/deployment.yaml (2.084kB)
 // fetcher/templates/service_account.yaml (1.088kB)
-// injector/templates/annotations.yaml (3.369kB)
+// injector/templates/annotations.yaml (3.689kB)
 // injector/templates/configmap.yaml (1.2kB)
 // injector/templates/javaagent.yaml (1.462kB)
 // oapserver/templates/cluster_role.yaml (1.241kB)
@@ -458,6 +458,16 @@
     defaultValue: "mkdir -p /sky/agent && cp -r /skywalking/agent/* /sky/agent"
     validateFunc: nil
     envName: nil
+  
+  - name: sidecar.skywalking.apache.org/initcontainer.resources.limits
+    defaultValue: nil
+    validateFunc: ValidateResourceRequirements
+    envName: nil
+
+  - name: sidecar.skywalking.apache.org/initcontainer.resources.requests
+    defaultValue: nil
+    validateFunc: ValidateResourceRequirements
+    envName: nil
 
   - name: sidecar.skywalking.apache.org/sidecarVolume.Name
     defaultValue: sky-agent
@@ -516,7 +526,7 @@
 	}
 
 	info := bindataFileInfo{name: "injector/templates/annotations.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
-	a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa6, 0x13, 0x6c, 0x84, 0xe7, 0x3, 0x54, 0x65, 0xb9, 0x8, 0xb1, 0x22, 0xe1, 0xf2, 0xea, 0x19, 0xea, 0xde, 0xeb, 0xf, 0x60, 0xb1, 0x83, 0xaf, 0x1d, 0x14, 0xde, 0x3c, 0x92, 0x56, 0x23, 0xc3}}
+	a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x59, 0xbb, 0xd0, 0x87, 0x78, 0x4, 0xac, 0x18, 0x3a, 0xf7, 0xff, 0xcc, 0x99, 0x72, 0x42, 0xd, 0xa4, 0xcb, 0xfa, 0x78, 0x6a, 0x39, 0xbd, 0xb8, 0xfd, 0x8b, 0x25, 0x26, 0x8f, 0xa, 0x9e, 0x1f}}
 	return a, nil
 }
 
diff --git a/test/e2e/demo.yaml b/test/e2e/demo.yaml
index 43c8211..0d7d0a4 100644
--- a/test/e2e/demo.yaml
+++ b/test/e2e/demo.yaml
@@ -29,6 +29,8 @@
         app: demo
       annotations:
         strategy.skywalking.apache.org/agent.Overlay: "true"
+        sidecar.skywalking.apache.org/initcontainer.resources.limits: '{"memory": "100Mi","cpu": "100m"}'
+        sidecar.skywalking.apache.org/initcontainer.resources.requests: '{"memory": "100Mi","cpu": "100m"}'
         agent.skywalking.apache.org/collector.backend_service: "oap-service:11800"
     spec:
       containers: